8

I'm using Entity Framework 5 in Database First approach and I am using edmx file.

Most of my entities have 6 common fields. Fields like CreatedAt, CreatedBy etc. Now, I implemented some functions as extensions that can only be applied to IQueryable of those Entities that have the common fields. But when I implement the extension method, it can be accessed by any type of IQueryable as it's typed T and I can only define that the type T should always be of one type.

So, I thought I can give a base class to the entities which has common fields and define type T as that base type. But, it seems I can't do this.

Any idea on how to solve this or implement what I have explained above?

Amila
  • 3,711
  • 3
  • 26
  • 42

2 Answers2

9

Don't create a base class. Create an Interface, like below:

public interface IMyEntity
{
    DateTime CreatedAt { get; set; }
    string CreatedBy { get; set; }
    // Other properties shared by your entities...
}

Then, your Models will be like this:

[MetadataType(typeof(MyModelMetadata))]
public partial class MyModel : IMyEntity
{
   [Bind()]  
   public class MyModelMetadata
   {
      [Required]
      public object MyProperty { get; set; }

      [Required]
      public string CreatedBy { get; set; }  
   }
}
ataravati
  • 8,891
  • 9
  • 57
  • 89
  • Thanks for your quick response. So, If I define the interface outside of edmx file. then where am I going to tell the entity to implement from that interface. It's not easy to manually edit all of the required entities as I will have to do it allover again when I update the edmx file. – Amila Aug 16 '13 at 14:38
  • 2
    You don't touch the auto-generated code. That's what partial classes are supposed to be used for. You create a partial class (under Models folder) for each of your entities in EF. That's where you can define a MetadataType for your Models (for data annotation). See the updated answer. – ataravati Aug 16 '13 at 14:41
  • Yes, I'm using MetadataType at the moment. But thought there might be an easy way of doing it i.e. like giving a base class to an entity, it would have been better if it allowed to give an interface as well within the diagram. Anyways, it loos like I will have to define the partial class for all the entities. Thanks for you quick help – Amila Aug 16 '13 at 14:48
  • What if you need to bind to the properties in IMyEntity or make them [Required]? Would you override the property in your partial class? – TheOptimusPrimus Aug 16 '13 at 16:29
  • Definitely the way to go. However if multiple objects are going to share the same interface, I don't recommend nesting the class in one of them. – Erik Philips Aug 16 '13 at 16:34
  • @TheOptimusPrimus, you don't have to do anything to bind to the properties in IMyEntity. They are just properties like the other ones. And, to use data annotation attributes like `[Required]` you use a MetadataType class like in the answer. – ataravati Aug 16 '13 at 17:25
  • But what if you want to make something like [CreatedAt] a [Required] attribute, but only in one instance and not the other instances? I would think you would have to override the property in your partial class? – TheOptimusPrimus Aug 16 '13 at 17:28
  • The MetadataType class is for a single entity not for the interface. So, you would use the attribute for the shared properties exactly the same way. However, in most cases, you don't even want to do that. You'd better share properties that are exactly the same in your entities. Fields like CreatedAt or CreatedBy are very good examples of these properties. See the updated answer. – ataravati Aug 16 '13 at 17:29
2

I'm a fan of:

public interface IShared
{
  DateTime CreatedOn { get; set; }
}

public interface ISharedValidation
{
  [Required]
  DateTime CreatedOn { get; set; }
}


public interface IMyEntity: IShared
{
  // Entity Specifics
  string Username { get; set; }
}

public interface IMyEntityValidation: ISharedValidation
{
  [Required]
  string Username { get; set; }
}

Then, your Models will be like this:

[MetadataType(typeof(IMyEntityValidation))]
public partial class MyModel : IMyEntity
{
  public object CreatedOn { get; set; }
  public string Username { get; set; }  
}

If T4 generated by Entity Framework then your non-autogenerated class would look like:

[MetadataType(typeof(IMyEntityValidation))]
public partial class MyModel : IMyEntity
{
}

Typically, it is not recommended to use Bind in Asp.Net MVC.

Community
  • 1
  • 1
Erik Philips
  • 53,428
  • 11
  • 128
  • 150