dimanche 28 août 2011

Managing default values for entities in EF: the from birth way

I recently face the problem of setting default value for entities when using entity framework.

After some walk around, here is a part of my actual solution.

This is not really the default values of the properties, but the default values of the types of the properties.

Please consider the following class:

using System;
using System.Linq;
using System.Reflection;


namespace AppXYZ.Entities {
    public static class EntityTools {
        public static readonly DateTime dtDef = new DateTime(1900, 1, 1, 0, 0, 0);

        public static void SetDefaults (object o) {
            Type T = o.GetType();
            foreach ( MemberInfo m in T.GetProperties() ) {
                PropertyInfo P = T.GetProperty(m.Name);
                switch ( Type.GetTypeCode(P.PropertyType) ) {
                    case TypeCode.String :
                        if ( P.GetValue(o, null) == null ) 
                            P.SetValue(o, String.Empty, null); 
                        break;
                    case TypeCode.DateTime :
                        if ( (DateTime)P.GetValue(o, null) == DateTime.MinValue )
                            P.SetValue(o, EntityTools.dtDef, null); 
                        break;
                }
            }
        }

        //T must have a constructor with 0 argument
        public static T GetNewEntity<T> () {
            T e;
            try {
                e = Activator.CreateInstance<T>();
            } catch {
                e = default(T);
            }
            SetDefaults(e);


            return e;
        }
    }
}

Since, I discover at least another way: the just on time way

mercredi 17 août 2011

Entity Framework: Code-First, Foreign Key One-To-Many

The object of this article is to (try to) illustrate two ways for configuring a one to many relation by using entity framework 4.1. For the need of the sample I use a very small and anecdotic part of the data model of Cegid Business Applications. That is I use code first on an existing database !!! :)

To help understanding differences, I comment code from one version to the other.

Of course you will need a connecion string:




Please note:

  • the activation of MARS

First: by using the Data Annotations

namespace ef {
    class Program {
        static void Main (string[] args) {
             CegidContext cc = new CegidContext();
            foreach ( gThirdParty gtp in (from t in cc.gThirdParties where t.GBusinesses.Count() > 0 select t) ) {
                 Console.WriteLine("{0,-17} : {1}", gtp.T_TIERS, gtp.GBusinesses.Count());
            }
        }
    }

    [Table("AFFAIRE")]
    public class gBusiness {
        [Key]
         public string AFF_AFFAIRE {get; set;}
         public string AFF_LIBELLE { get; set; }
         public string AFF_TIERS { get; set; }
 
        [ForeignKey("AFF_TIERS")]
         public virtual gThirdParty GThirdParty { get; set; }
    }

    [Table("TIERS")]
    public class gThirdParty {
         public gThirdParty () { 
            GBusinesses = new List<gBusiness>();
        }

        [Key]
         public string T_TIERS { get; set; }
         public string T_LIBELLE { get; set; }
         public virtual ICollection<gBusiness> GBusinesses { get; set; }
    }


    /*public class gBusinessConfiguration
        : EntityTypeConfiguration<gBusiness> {
        public gBusinessConfiguration ()
            : base() {
            HasKey(p => p.AFF_AFFAIRE);
            HasRequired(p => p.GThirdParty).WithMany(t => t.GBusinesses).Map(x => x.MapKey("AFF_TIERS")); 
        }
    }

    public class gThirdPartyConfiguration
        : EntityTypeConfiguration<gThirdParty> {
        public gThirdPartyConfiguration ()
            : base() {
            HasKey(p => p.T_TIERS);
        }
    }*/    
    
    public class CegidContext : DbContext {
        public DbSet<gBusiness> gBussinesses { get; set; }
        public DbSet<gThirdParty> gThirdParties { get; set; }

        /*protected override void OnModelCreating (DbModelBuilder modelBuilder) {
            modelBuilder.Configurations.Add(new gBusinessConfiguration());
            modelBuilder.Configurations.Add(new gThirdPartyConfiguration());
            base.OnModelCreating(modelBuilder);
        }*/
    }
}

Second: by using the fluent API

namespace ef { 
    class Program { 
        static void Main (string[] args) {
            CegidContext cc = new CegidContext();
            foreach ( gThirdParty gtp in (from t in cc.gThirdParties where t.GBusinesses.Count() > 0 select t) ) {
                 Console.WriteLine("{0,-17} : {1}", gtp.T_TIERS, gtp.GBusinesses.Count());
            }
        }
    }

    [Table("AFFAIRE")]
    public class gBusiness { 
        //[Key] 
         public string AFF_AFFAIRE {get; set;} 
         public string AFF_LIBELLE { get; set; } 
         //public string AFF_TIERS { get; set; } 
              
        //[ForeignKey("AFF_TIERS")] 
         public virtual gThirdParty GThirdParty { get; set; } 
    }

    [Table("TIERS")] 
     public class gThirdParty { 
         public gThirdParty () { 
            GBusinesses = new List<gBusiness>(); 
        }

        //[Key] 
         public string T_TIERS { get; set; } 
         public string T_LIBELLE { get; set; } 
         public virtual ICollection<gBusiness> GBusinesses { get; set; } 
    }

    public class gBusinessConfiguration 
       : EntityTypeConfiguration<gBusiness> { 
        public gBusinessConfiguration () 
           : base() { 
           HasKey(p => p.AFF_AFFAIRE); 
           HasRequired(p => p.GThirdParty).
               WithMany(t => t.GBusinesses).
               Map(x => x.MapKey("AFF_TIERS")); 
       } 
    }

    public class gThirdPartyConfiguration 
        : EntityTypeConfiguration<gThirdParty> { 
         public gThirdPartyConfiguration () 
            : base() { 
            HasKey(p => p.T_TIERS); 
        } 
    }

    public class CegidContext : DbContext { 
         public DbSet<gBusiness> gBussinesses { get; set; } 
         public DbSet<gThirdParty> gThirdParties { get; set; }
 
         protected override void OnModelCreating (DbModelBuilder modelBuilder) { 
            modelBuilder.Configurations.Add(new gBusinessConfiguration()); 
            modelBuilder.Configurations.Add(new gThirdPartyConfiguration()); 
            base.OnModelCreating(modelBuilder); 
        } 
    } 
}

Enjoy

Pending question:

  • How to avoid lazy loading and force explicit loading as Linq to SQL allows with DataLoadOption in the DataContext.

Edit -----


About not lazy, here is the way: cc.gThirdParties.Include("GBusinesses")

lundi 1 août 2011

Ninject by the sample I

Here you will find 2 samples that I wrote to help me materializing the "magic" of Ninject and more generally of DI.

using System;

using Ninject;
using Ninject.Modules;

namespace simplInject {

class Program {
    static void Main (string[] args) {
        IKernel ik = new StandardKernel(new imod());
                  
        //constructor with 2 interfaces.
        I3 c = ik.Get<I3>(); // will "magically" instanciate C1 and C2 instances from the binding
        Console.WriteLine("{0} with {1} C1 instance", c.concat, C1.cpt);
        //constructor with 1 interface and 1 parameter.
        I4 c4 = ik.Get<I4>(); // // will "magically" instanciate another C1 instance from the binding
        Console.WriteLine("{0} with {1} C1 instance", c4.concat, C1.cpt);
    }
}

class imod : NinjectModule {
    public override void Load () {
        //Here the WithconstructorArgument is to trace the binding in the main method.
        Bind<I1>().To<C1>().WithConstructorArgument("s", "string I");
        Bind<I2>().To<C2>().WithConstructorArgument("s", "string II");
        Bind<I3>().To<C3>();
        Bind<I4>().To<C4>().WithConstructorArgument("s", "string III");
   }

}

public interface I1 {
    string s1 { get; set; }
}
public interface I2 {
    string s2 { get; set; }
}
public interface I3 {
    string concat { get; }
}
public interface I4 {
     string concat { get; }
}

public class C1 : I1 {
    public static int cpt = 0;
    private int _id;
    string _s;
          
    public C1 (string s) {
        _id = C1.cpt++;
        _s = s;
    }

    public int Id { get { return _id; } }
 
    public string s1 {
        get { return this._s; }
        set { this._s = value; }
    }
}

public class C2 : I2 {
    string _s;

    public C2 (string s) {
        this._s = s;
    }

    public string s2 {
        get { return this._s; }
        set { this._s = value; }
    }
}

public class C3 : I3 {
    I1 _c1; I2 _c2;
          
    public C3(I1 c1, I2 c2) {
        _c1 = c1; _c2 = c2;
    }

    public string concat {
        get { return _c1.s1 + " " + _c2.s2; }
    }
}

public class C4 : I4 {
    I1 _c1; string _s;

    public C4 (string s, I1 c1) {
        _c1 = c1;
        _s = s;
    }

    public string concat {
        get { return _s + " " + _c1.s1; }
    }
}

}