strenium50
strenium50

Reputation: 21

Retrieving an Entity Object by name - LINQ to Entities, EF 4.0

I have a number of entity objects that are structurally the same but the naming convention is different e.g Products1, Products2, Products3 (this is part of the legacy db schema and I can't do much about this).

These classes are of different types as far as CLR is concerned and unfortunately since the design code is auto-generated I can't slap an interface on these guys to show commonality. So, my question is: Is there a way to retrieve the entity object by name?

I'd basically like to avoid switch/case business when applying essentially the same logic to these objects.

Upvotes: 2

Views: 698

Answers (3)

Adam Rackis
Adam Rackis

Reputation: 83358

You could build an Expression tree to query for the object or objects in question:

public T GetSingleObject<T>(int someValue) {
    MyEntities db = new MyEntities();
    var result = db.CreateQuery<T>(String.Format("[{0}]", typeof(T).Name + "s"));

    var param = Expression.Parameter(typeof(T));

    var lambda = Expression.Lambda<Func<T, bool>>(
        Expression.Equal(
            Expression.Property(param, "WhateverPropertyYourComparing"),
            Expression.Constant(someValue)),
        param);

    return result.SingleOrDefault(lambda);
}

Or if you want a collection of objects

public IEnumerable<T> GetResultCollection<T>(int someValue) {
    MyEntities db = new MyEntities();
    var result = db.CreateQuery<T>(String.Format("[{0}]", typeof(T).Name + "s"));

    var param = Expression.Parameter(typeof(T));

    var lambda = Expression.Lambda<Func<T, bool>>(
        Expression.Equal(
            Expression.Property(param, "WhateverPropertyYourComparing"),
            Expression.Constant(someValue)),
        param);

    return result.Where(lambda);
}

Of course if your desired query is very long, this can get out of hand, and you should consider adding in the necessary interface using partial classes, as Justin Morgan suggested.

Note that this method assumes that your ObjectSet collection is the same name as your object, plus an "s", ie, "Invoice" to "Invoices". If that's not the case, ie, "Person" to "People", then you could use System.Data.Entity.Design.PluralizationServices.PluralizationService to get the proper name

Upvotes: 2

BrokenGlass
BrokenGlass

Reputation: 160862

Since the EF4 classes are partial classes you can actually extend them and make them implement an interface of your choice, all in a separate file.

An alternative to that would be using dynamic - just instantiate the entity based on it's type.

dynamic myEntity= Activator.CreateInstance(Type.GetType("EntityTypeHere")));
myEntity.CommonProperty = "Foo";

The big disadvantage here is that you lose all type safety at compile time - any problem you will only discover at runtime, also it's slower than the statically typed approach.

Upvotes: 1

Justin Morgan
Justin Morgan

Reputation: 30715

Depending on how many classes we're talking about, and how flexible you need to be, interfaces might not be out of the question. I've done something similar using generics:

//WARNING: Partially-remembered code ahead...
interface IDuckEntity
{
    int FeatherCount { get; set; }
}

public partial class Products1 : IDuckEntity { }
public partial class Products2 : IDuckEntity { }
public partial class Products3 : IDuckEntity { }

//in some other class:
void DoStuff<T>(T entity) where T : EntityObject, IDuckEntity
{
     entity.FeatherCount = 500;
}

So basically, you set up a separate file where you put the interface and a bunch of those little partial class declarations. Then you'll have access to the common structure. I don't know what your exact situation is, but this worked like a charm for me.

Upvotes: 0

Related Questions