wake-up-neo.net

EntityFramework Objekt nach ID abrufen?

Ist es mit Generics möglich, ein Objekt aus meinem EntityFramework abzurufen, ohne den Typ zu kennen?

Ich denke an etwas wie:

public T GetObjectByID<T>(int id)
{
   return (from i in myDatabase.T where i.ID == id select i);
}

Ist das machbar? Könnte ich Reflection verwenden, um T.GetType().Name irgendwie für die Tabelle zu verwenden?

BEARBEITEN
Ein weiteres Aufhängen ist, dass nicht alle mir zur Verfügung stehenden Tabellen "ID" als eindeutigen Spaltennamen verwenden.

20
James P. Wright

Endlich das Problem damit gelöst:
http://Pastebin.com/kjXUKBNS

Um den Code aufzurufen, verwende ich Folgendes: 

// Get the id of the object we are saving
PropertyInfo prop = GetProperty<TEntity>(entity, entity.EntityKey.EntityKeyValues[0].Key);
string entityID = prop.GetValue(entity, null).ToString();

// Get the current version of this object
var originalEntity = GetEntity<TEntity>(PropertyEquals, entityID);

Es wird davon ausgegangen, dass der Primärschlüssel, nach dem Sie suchen, der erste in der Liste der Primärschlüssel ist.

3
James P. Wright

Sie können eine Schnittstelle definieren, die von allen Ihren Entitäten implementiert wird:

public interface IEntity
{
    int Id { get; }
}

und Methode zum Abrufen Ihrer Entität:

public T GetObjectById<T>(int id) where T : class, IEntity
{
    return context.CreateObjectSet<T>().SingleOrDefault(e => e.Id == id);
}

Sie können auch einen ähnlichen Ansatz verwenden wie in der verlinkten Frage . Sie müssen nur eine andere Methode verwenden, um Ihre Entität zu erhalten:

public virtual T GetByKey<T>(int id) where T : class, IEntity
{
     string containerName = context.DefaultContainerName;
     string setName = context.CreateObjectSet<T>().EntitySet.Name;
     // Build entity key
     var entityKey = new EntityKey(containerName + "." + setName, "Id", id);
     return (TEntity)Context.GetObjectByKey(entityKey);         
}

Der Unterschied ist, dass die erste Methode immer die Datenbank abfragt, selbst wenn Sie die Instanz bereits in den Kontext geladen haben, während die zweite Methode zuerst prüft, ob die Instanz bereits geladen ist. Die Methode ist nicht so effizient, da diese Namen immer wieder erstellt werden. Hier ist ein allgemeiner Ansatz, der mit jedem Schlüsseltyp und -namen arbeiten kann und hier Ansatz, der mit komplexen Schlüsseln arbeitet.

Keine dieser Methoden funktioniert direkt mit der Vererbung. Sie müssen den Basistyp angeben, damit sie funktioniert.

30
Ladislav Mrnka

Ich denke, dass die Find()-Methode in der Lage ist zu tun, was Sie suchen ( DbSet.Find-Methode ).

var someEntity = dbSet.Find(keyValue);
22
Yuck

Es ist schwierig, eine vollständig generische Lösung zu entwickeln, da Entitäten zusammengesetzte Schlüssel haben können. Dies funktioniert jedoch für einen einfachen Einzelfall.

Der Schlüssel besteht darin, T auf den Typ System.Data.Objects.DataClasses.EntityObject zu beschränken, der dann die Eigenschaft EntityKey hat (die den Primärschlüssel darstellt).

static T GetById<T>(object id) where T : EntityObject
{
    using (var context = new MyEntities())
    {
        return context.CreateObjectSet<T>()
            .SingleOrDefault(t => t.EntityKey.EntityKeyValues[0].Value == id);
    }
}
5
Kirk Broadhurst

Eine andere Möglichkeit, Entität aus der ID im Entity-Framework abzurufen

public T Get<T>(int id) where T : EntityObject;
{
var ObjectSet = _context.CreateObjectSet<T>();
var PropName = ObjectSet.EntitySet.ElementType.KeyMembers[0].ToString();
return  ObjectSet.Where("it." + PropName + "=" + id).FirstOrDefault();
}

Ergebnis

SELECT TOP (1) 
[Extent1].[CatId] AS [CatId], 
[Extent1].[CatName] AS [CatName], 
[Extent1].[CatType] AS [CatType],  
FROM [dbo].[Categories] AS [Extent1]
WHERE [Extent1].[CatId] = 1
3

Ich denke, das könnte helfen

public static TEntity Find<TEntity>(this ObjectSet<TEntity> set, object id) where TEntity : EntityObject
    {
      using (var context = new MyObjectContext())
      {
        var entity = set.Context.CreateObjectSet<TEntity>();
        string keyName = entity.FirstOrDefault().EntityKey.EntityKeyValues.FirstOrDefault().Key;

        return entity.Where("it." + keyName + " = " + id).FirstOrDefault();
      }
    }
2
Mustafa Magdy

Was ich getan habe, ist die Definition einer "KeyComparator" -Schnittstelle:

public interface IHasKeyComparator<TObject> {
   Expression<Func<TObject, bool>> KeyComparator { get; } 
}

Und dann können Sie es auch mit einem mehrwertigen Schlüssel an einem Objekt implementieren:

public sealed class MultiKeyedObject : IHasKeyComparator<MultiKeyedObject> {
   public int ID1 { get; set; }
   public string ID2 { get; set; }       

   readonly Expression<Func<MultiKeyedObject, bool>> mKeyComparator;

   public Expression<Func<MultiKeyedObject, bool>> KeyComparator {
      get { return mKeyComparator; }
   }

   public MultiKeyedObject() {
      mKeyComparator = other => other.ID1 == ID1 && other.ID2 == ID2;
   }
}

Und kann es generisch verwenden, wenn Sie die Einschränkung angeben:

public TObject Refresh<TObject>(TObject pObject)
where TObject : IHasKeyComparator<TObject> {
   return this.Set<TObject>().Single(pObject.KeyComparator);
}

Auf diese Weise müssen Sie jedoch über eine Instanz des Objekts verfügen, obwohl Sie eine leere mit Schlüsselwerten füllen und diese dann zum Abrufen aus der Datenbank verwenden können.

0
Dave Cousineau