EF 5 Model First Partial Class Custom Constructor How To?
Asked Answered
E

5

10

EF has generated for me some partial classes, each with a constructor, but it says not to touch them (example below), now if I make my own secondary partial class and I want to have a constructor that automatically sets some of the fields how do I do so as it would conflict?

//------------------------------------------------------------------------------
// <auto-generated>
//    This code was generated from a template.
//
//    Manual changes to this file may cause unexpected behavior in your application.
//    Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace Breakdown.Models
{
    using System;
    using System.Collections.Generic;

    public partial class Call
    {
        public Call()
        {
            this.Logs = new HashSet<Log>();
        }

        ...
    }
}
Erasure answered 23/1, 2013 at 16:53 Comment(0)
E
20

Partial methods can help you here, in the T4 Templates define a body-less partial method and call that inside the constructor.

public <#=code.Escape(entity)#>()
{
    ...
    OnInit();
}

partial void OnInit();

Then in your partial class define the partial method and place inside that what you want to do in the constructor. If you don't want to do anything then you don't need to define the partial method.

partial class Entity()
{
    partial void OnInit()
    {
        //constructor stuff
        ...
    }
}

http://msdn.microsoft.com/en-us/library/vstudio/6b0scde8.aspx

Eventempered answered 25/5, 2013 at 3:19 Comment(2)
Will the T4 template be overwritten when the model is updated? Why didn't Microsoft include this?Fluorometer
No, changes in the generated classes will be overwritten but not the template itself. The template's role is to generate the classes from the model hence why changes there are safe. My guess why Microsoft didn't include this by default was probably to keep the generated classes as clutter free as possible since they've given programmers the ability to customize it how they want.Eventempered
M
1

This is not possible.

Partial classes are essentially parts of the same class.

No method can be defined twice or overridden (same rule apply for the constructor also)

But You can use below mentioned Workaround :

//From file SomeClass.cs - generated by the tool
public partial class SomeClass
 {
    // ...
 }


// From file SomeClass.cs - created by me
public partial class SomeClass
  {
    // My new constructor - construct from SomeOtherType
    // Call the default ctor so important initialization can be done
    public SomeClass(SomeOtherType value) : this()
      {

       }
  } 

for more information check Partial Classes, Default Constructors

I hope this will help to you.

Manipur answered 23/1, 2013 at 18:3 Comment(3)
Yes I know I can make a constructor with arguments but really I don't have arguments or want any.Erasure
@MuhammadA Then unfortunately you can't.As I mentioned top part of my post.Manipur
While you cant redefine a constructor with the same signature within partial classes you can remove the constructor from the auto generated class allowing you to manually implement it.Raymundorayna
R
1

I wanted to do the same recently and ended up modifying the T4 template so I could implement my own parameterless constructor manually. To accomplish this you can remove the constructor from the generated classes and move the instantiation of collections etc to outside the constructor so this:

public Call()
{
  this.Logs = new HashSet<Log>();
}

becomes this:

private ICollection<Log> logs = new HashSet<Log>();
public virtual ICollection<Log> Logs 
{ 
  get { return this.logs; } 
  set { this.logs = value; } 

}

The drawback I suppose is that the generated classes are not as "clean". That is you can't just have auto-implemented properties for your complex/nav types.

In your model.tt file you can prevent the constructor generation by removing the below code, commenting it out or by just putting in a false into the conditional so it never gets executed:

if (propertiesWithDefaultValues.Any() || complexProperties.Any())
{
#>
  public <#=code.Escape(complex)#>()
  {
<#
    foreach (var edmProperty in propertiesWithDefaultValues)
    {
#>
      this.<#=code.Escape(edmProperty)#> =
         <#=typeMapper.CreateLiteral(edmProperty.DefaultValue)#>;
<#
    }

    foreach (var complexProperty in complexProperties)
    {
#>
      this.<#=code.Escape(complexProperty)#> = new
        <#=typeMapper.GetTypeName(complexProperty.TypeUsage)#>();
<#
    }
#>
  }

Then below this you need to do some modification where properties are generated for your complex and navigation types. Add a private var with object instantiation and a property for accessing the private var for each of these eg:

if (complexProperties.Any())
{
  foreach(var complexProperty in complexProperties)
  {
    //generate private var + any instantiation
    //generate property for accessing var
  }
}

Depending on the complexity of your model there may be other areas you need to modify. Hopefully this gets you started.

Raymundorayna answered 23/1, 2013 at 20:28 Comment(0)
D
0
  1. Add a base class:

     public class CallBase
     {
            protected CallBase()
            {
                Initialize();
            }
    
            protected abstract void Initialize();
     }
    
  2. Add the partial class implementation in another file

     public partial class Call: CallBase
     {
        protected override void Initialize();
        {
       ...
         }
     }
    

The drawback is that the Initialization method will be called before the all collection creature.

Dropforge answered 22/4, 2013 at 8:45 Comment(0)
W
0

If I well understand the question, you need this constructor when creating a new entity, that is an entity that was not persisted before.

My case was to set a default value to all datetime, that is initalize them to "the begining of time" : 1900-01-01.

In this case I use an entity factory

public static T GetNewEntity<T> () {
    T e;
    try {
        e = Activator.CreateInstance<T>();
    } catch {
        e = default(T);
    }
    SetDefaults(e);

    return e;
}

Each time I need a new Entity I use

Entity e = GetNewEntity<Entity>();

with SetDefaults as :

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;
        }
    }
}

full code is here

It could be rewrittent to consider the entity type and so on...

Walden answered 15/7, 2014 at 8:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.