Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

oren@ravendb.net +972 52-548-6969

Posts: 7,524
|
Comments: 51,148
Privacy Policy · Terms
filter by tags archive
time to read 2 min | 283 words

I'm thinking about the way ASP.Net are working, and I can't help thinking that I'm missing something with regard to partial classes. The issue here is that of how the compiler knows to take the aspx page and turn it into code.

Is it done it the compiler level in the first place? If so, how does the compiler knows about it? Is it possible to get your own code to run when this is done?

I think that the answer to those is no, and that it is just the magic of ASP.Net & VS.Net that make it looks like it's happening. And ideas about it? I'm interested in generating add-on content for a class during compilation, and I think that partial classes and attribute based code generation might put me on an more even footing on C# as I am on Boo.

Right now it looks like I need to:

  • Write a Custom Tool to do it, and register as a pre compilation step in VS.Net (MsBuild?)
  • Parse the source files, in order to figure out which class has the correct attributes. Any suggestions on how to do that? I need to do it before compilation.
  • Spit out gobs of code.

The part about parsing worries me, it not going to be pleasant to do, and I can't think of an easy way to get the AST for a C# file.

My First Trigger

time to read 7 min | 1336 words

So, today I wrote my first trigger. The issue was of data replication on a hierarchial structure. When the parent is updated, all the children should be as well. If a child is update, the link to the parent is severed. The number of children is unlimited, so I can't use NHibernate to do the update, as it would be horribly inefficent to do batch update with it.

The parent and child in this case is one of ~15 classes (one inheritance family) that has different meaning for the same fields in the database. They are mapped using Table Per Inheritance in NHiberante (using ActiveRecord). At first I despaired from doing this properly, I thought about having to do it 15 times, with minor modifications... Even seperating the common functionality, I would still have a lot to write. Then I remembered that I'm using ActiveRecord, and that it can gives me the information about a class, so I quickly wrote this code:

/// <summary>
/// Copies all the values of the current parent rule to all its children
/// iterate over the model for the rule and gets all the properties and fields.
/// </summary>
protected virtual void UpdateChildren(IDbConnection connection)
{
 using (IDbCommand command = connection.CreateCommand())
 {
  command.CommandText = Resources.UpdateAllChildRules;
  CrearteParameters(command);
  command.ExecuteNonQuery();
 }
}
protected virtual void CrearteParameters(IDbCommand command)
{
 ActiveRecordModel model = ActiveRecordBase.GetModel(this.GetType());
 foreach (PropertyModel propModel in model.Properties)
 {
  CreateParameter(command, propModel.PropertyAtt.Column,
   propModel.Property.GetValue(thisnull),
   propModel.Property.PropertyType);
 }
 foreach (FieldModel fieldModel in model.Fields)
 {
  CreateParameter(command, fieldModel.FieldAtt.Column,
   fieldModel.Field.GetValue(this),
   fieldModel.Field.FieldType);
 }
}
protected void CreateParameter(IDbCommand command, string name, 
 object value, Type type)
{
 IDataParameter param = command.CreateParameter();
 if (type.IsDefined(typeof(ActiveRecordAttribute),false))
 {
  ActiveRecordModel model = ActiveRecordBase.GetModel(type);
  PrimaryKeyModel pkModel = (PrimaryKeyModel) model.Ids[0];
  type = pkModel.Property.PropertyType;
  value = pkModel.Property.GetValue(value, null);
 }
 param.ParameterName = "@" + name;
 param.Value = value;
 param.DbType = GetDbType(type);
}

As I wrote this code, I kept muttering things about Evil Code and how the one to follow after wouldn't be able to understand anything. This is using some deeply internal knowledge of Active Record, and it's not very nice for someone who doesn't know how Active Record works. I just couldn't see a better way. And considerring my options, I thought that this was the least Evil among them.

Then a friend offered me to use a simple thing. Triggers. The database I'm using for the project in SQL Server 2000, so that is not a problem, but while I leapt at the idea (much clearner than the above code), but there was an implementation hurdle to go through, I never wrote a trigger before, certainly not for SQL Server. The only one around I could ask used to write triggers for Oracle, which wasn't much help.

So I scoured the books online, and discovered what I already knew, that SQL is a very different language than my safe OO world. I think that I got it write, and small tests shows that it's working properly, but I'm still not sure about it.

CREATE TRIGGER TR_Update_RuleChildren_On_Rule_Update     
ON [Rules]
FOR UPDATE AS
SET NOCOUNT ON
DECLARE @UpdatedRuleId int, @UpdatedSeverity tinyint,
@UpdatedTemplateRuleId int
SELECT @UpdatedRuleId = [RuleId], @UpdatedSeverity = [Severity],
@UpdatedTemplateRuleId = [TemplateRuleId] FROM [Inserted]
IF (@UpdatedTemplateRuleId IS NULL) -- is a parent rule
BEGIN
UPDATE [Rules] SET [Severity] = @UpdatedSeverity
WHERE [TemplateRuleId] = @UpdatedRuleId
END
ELSE
UPDATE [RULES] SET [TemplateRuleId] = NULL
WHERE [Rules].[RuleId] = @UpdatedRuleId
SET NOCOUNT OFF
go

As I said, this is the very first I've written, so I'm absolutely not certain if I did it right. Is this the way to do? It make me cringe to see it, since it violate so many things I know are right. But I guess that they don't apply to a database.

PDC Videos

time to read 1 min | 106 words

I currently watching Raymond Chen talk. It's so cool to be able to see what all the excitement was about. It a shame that the price for the DVD set is so high (500$ ?!).

I'm really glad that Microsoft decided to make them avialable, even if not to the FireFox using crowd. I'm scanning the archives now, looking for good talks. There is so much stuff there.

Rico Mariani's presentations, GC Inside out, Concurrency, etc.

Best quote so far, from Raymond's talk: "I can do nothing really fast."

#Develop Update

time to read 1 min | 159 words

The #Develop IDE just got a whole lot better, they fixed the generic type inferencing.

? dic = new Dictionary<string, List<KeyValuePair<string,int >>>();

Turns to:

Dictionary <string, List<KeyValuePair<stringint >>> dic = 
     new Dictionary<string, List<KeyValuePair<string,int >>>(); 

time to read 10 min | 1806 words

I've a confession to make. It's a very serious one. I don't like strings and Reflection. In fact, you could say that I hate them with a passion. I hate them because they hide important information from the compiler. This post is actually not a rant, it presents a solution to the problem.

I hate them so much that I wrote my own Mocking Framework that don't use strings at all. .Net has some really great stuff that you can do with Reflection, but it has two big problems.

  • It is a performance hit.
  • It uses strings.

I refactor a lot, and I just hate it when everything compiles okay, and then things breaks on runtime. I think that static reflection will enable writing amazing code. The functionality is already built into the CLR (check the ldtoken/ldftn IL instructions and friends). It didn't make it into the 2.0 release, but I hope that it will be in the next release. In the meantime, the 2.0 Reflection has been optimized, so that is what we have for now. But it's not enough for me. I discovered that you can do this:

Action<int> act = this.CalcSums;

So I figured out that I can create a library that would cheat the C# compiler (and I belive the VB.Net compiler as well) to give me a token for the method. Before I'll get into the details, here is a short sample of the code:

using System;
using System.Reflection;
public class StaticReflection
{
        #region void delegates
        public delegate void VoidFunc();
        public delegate void VoidFunc<A0>(A0 a0);
        #endregion
        #region delegates
        public delegate TRet Func<TRet>();
        public delegate TRet Func<TRet, A0>(A0 a0);
        #endregion
        #region void func Method Info
        public static MethodInfo VoidMethodInfo(VoidFunc func0)
        {
                return func0.Method;
        }
        public static MethodInfo VoidMethodInfo<A0>(VoidFunc<A0> func1)
        {
                return func1.Method;
        }
        #endregion
        #region func Method Info
        public static MethodInfo MethodInfo<TRet>(Func<TRet> func0)
        {
                return func0.Method;
        }
        public static MethodInfo MethodInfo<TRet, A0>(Func<TRet, A0> func1)
        {
                return func1.Method;
        }

        #endregion
}

The usage is simple:

public class Test
{
 public static void Main(string[]args)
 {
  MethodInfo thisMethod = StaticReflection.MethodInfo<int,int>(MultiplyByThree);
  Console.WriteLine(thisMethod);
 }
 
 public static int MultiplyByThree(int i)
 {
  return i * 3;
 }
}

The output of the above code is: "Int32 MultiplyByThree(Int32)"

Now, there is one huge advantage of this system, and it's the simple fact that it will fail to compile if you changed the name of the method and not the calling code. The other advantage it should have is in performance.

In order to test that I created two sets of tests. The tests are two classes, each with 10,000 methods, each class Main() needs to get a MethodInfo object for each of the methods. Here is a sample of the code:

Benchmarking the static reflection:

public static void Main(string [] args)
{
 DateTime start = DateTime.Now;
 MethodInfo method;
 method = StaticReflection.VoidMethodInfo(DemoClass0.DemoMethod0);
// ... 9998 more statements ... 
 method = StaticReflection.VoidMethodInfo(DemoClass9999.DemoMethod9999);
 Console.WriteLine("Took: {0}", DateTime.Now - start);
}

Benchmarking normal Reflection:

public class TestingUsingReflection
{
 public static MethodInfo GetMethod(Type type, string method)
 {
  return type.GetMethod(method);
 }
 
 public static void Main(string [] args)
 {
  DateTime start = DateTime.Now;
  MethodInfo method;
  method = GetMethod(typeof(DemoClass0),"DemoMethod0");
// ... 9998 more statements ... 

  method = GetMethod(typeof(DemoClass9999),"DemoMethod9999");
  Console.WriteLine("Took: {0}", DateTime.Now - start);
 } 

Here are the results.

Reflection .Net 2.0 & 1.1  218 - 187 Milliseconds
Static Delegates 125 Milliseconds

It's not a huge difference in the number, but it's something. And it's for 10,000 iterations. I was actually surpirsed that this happened. There doesn't seem to be any difference between 1.1 & 2.0 in this case (I imagine that it's not one that they optimized.) Using the static delegates took exactly 125 milliseconds each time I run it. It's not the performance that I'm looking at as the biggest advantage, it's the type safety in compile time.

Some things to note, there are two methods on the Static Reflection class, one for methods that has a return type, and one for those who don't. You can read the reason for that in Representing void methods with generic delegates.

The code (including the scripts I've used for generating the class and the benchmarks) are here. (You'll need Boo in order to run the benchmarks)

Enjoy,

time to read 1 min | 72 words

For the last 20 days or so, Brail wasn't part of the Castle's build, beause of the changes in how testing is done. It took me some time, mainly because I couldn't really devote any real length time to this. So now Brail's tests support the Castle.MonoRail.TestSupport, and I can investigate some interesting changes that were made in both Boo and the view engine for MonoRail.

FUTURE POSTS

  1. Querying over the current time in RavenDB - 2 hours from now

There are posts all the way to Oct 11, 2024

RECENT SERIES

  1. Challenge (75):
    01 Jul 2024 - Efficient snapshotable state
  2. Recording (14):
    19 Jun 2024 - Building a Database Engine in C# & .NET
  3. re (33):
    28 May 2024 - Secure Drop protocol
  4. Meta Blog (2):
    23 Jan 2024 - I'm a JS Developer now
  5. Production Postmortem (51):
    12 Dec 2023 - The Spawn of Denial of Service
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats
}