如何获取 ObjectSet<T> 的实体键名?

6

我在通用存储库中创建了一个通用的ObjectSet<T>

我想要得到ObjectSet<T>EntityKeyname,以便我可以在DataContext.GetObjectByKey中使用它。

我已经搜索和深入挖掘了,但似乎无法在ObjectSet类中找到此值。

7个回答

6

我之前曾经寻找过一种好的方法来实现这个功能,但是没有找到。通常我会在某个地方构建一个GetEntityByKey扩展方法,在其中使用字符串拼接来构建实体键以进行TryGetObjectByKey调用。构建实体键的一般思路如下:

internal class Program
{
    private static void Main(string[] args)
    {
        var dc = new AdventureWorksLT2008Entities();
        object c;
        dc.TryGetObjectByKey(GetEntityKey(dc.Customers, 23), out c);
        var customer = c as Customer;
        Console.WriteLine(customer.EmailAddress);
    }

    private static EntityKey GetEntityKey<T>(ObjectSet<T> objectSet, object keyValue) where T : class
    {
        var entitySetName = objectSet.Context.DefaultContainerName + "." + objectSet.EntitySet.Name;
        var keyPropertyName = objectSet.EntitySet.ElementType.KeyMembers[0].ToString();
        var entityKey = new EntityKey(entitySetName, new[] {new EntityKeyMember(keyPropertyName, keyValue)});
        return entityKey;
    }
}

您也可以做类似的事情。这个示例假设每个EntityKey只有一个字段,为了简单起见 - 对于多值键,您需要使用ObjectSet<T>.ElementType.KeyMembers稍微复杂一些,并将所有键传递到EntityKey构造函数中。


2

通用:

public class GenericoRepositorio<T> : IGenericoRepositorio<T> where T : class
{
    protected readonly ObjectSet<T> ObjetoSet;
    protected readonly ModeloContainer Contexto;

    public GenericoRepositorio(ModeloContainer contexto)
    {
        Contexto = contexto;
        ObjetoSet = Contexto.CreateObjectSet<T>();
    }

    public T Carregar(int id)
    {
        object objeto;
        Contexto.TryGetObjectByKey(GetEntityKey(ObjetoSet, id), out objeto);
        return (T)objeto;
    }

    private static EntityKey GetEntityKey<T>(ObjectSet<T> objectSet, object keyValue) where T : class
    {
        var entitySetName = objectSet.Context.DefaultContainerName + "." + objectSet.EntitySet.Name;
        var keyPropertyName = objectSet.EntitySet.ElementType.KeyMembers[0].ToString();
        var entityKey = new EntityKey(entitySetName, new[] { new EntityKeyMember(keyPropertyName, keyValue) });
        return entityKey;
    }
}

1

这应该为ObjectSet提供所有通用参数(类型):

objectSet.GetType().GetGenericArguments().First()

1

请查看我关于获取EntitySetName的这篇文章。对于我的存储库,我创建了一个属性,用于获取特定类名的实体集名称,以执行您正在尝试的操作。


0

已使用 EF 6 进行测试。

它将为给定的 DbEntityEntry 的每个主键值返回一个对象数组。

也许存在一些极端情况,它可能不起作用——但对于我简单的需求非常有效。

希望能帮助到其他人。

object[] GetPrimaryKeyValue(DbEntityEntry entry)
{
    List<object> key = new List<object>();

    var objectStateEntry = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(entry.Entity);
    if (objectStateEntry.EntityKey.EntityKeyValues != null && objectStateEntry.EntityKey.EntityKeyValues.Length==1)
    {
        key.Add(objectStateEntry.EntityKey.EntityKeyValues[0].Value);
    }
    else
    {
        if (objectStateEntry.EntitySet.ElementType.KeyMembers.Any())
        {
            foreach (var keyMember in objectStateEntry.EntitySet.ElementType.KeyMembers)
            {
                if (entry.CurrentValues.PropertyNames.Contains(keyMember.Name))
                {
                    var memberValue = entry.CurrentValues[keyMember.Name];
                    if (memberValue != null)
                    {
                        key.Add(memberValue);
                    }
                }
            }
        }
    }
    return key.ToArray();
}

0

var objContext = ((IObjectContextAdapter)this.context).ObjectContext;

var objSet = objContext.CreateObjectSet<T>();

var entityKey = objContext.CreateEntityKey(objSet.EntitySet.Name, entityToUpdate);

Object foundEntity;

var exits = objContext.TryGetObjectByKey(entityKey, out foundEntity);

if (exits && this.dbset.Local != null && this.dbset.Local.Contains(foundEntity) &&this.dbset.Local.Any())                    
{
  if (entityKey.EntityKeyValues != null && entityKey.EntityKeyValues.Any())                       
  {       
    DbEntityEntry<T> entry = this.context.Entry(this.dbset.Find(entityKey.EntityKeyValues.FirstOrDefault().Value));
                        entry.CurrentValues.SetValues(entityToUpdate);
   }
}

this.context.SaveChanges();

0

我曾经尝试过类似的事情,即在类型未知的情况下,在运行时获取主键名称和值。我只是试图实现一个删除审计方案,但每个解决方案都涉及到我不太理解的多余代码。从DbContext中无法获取EntityKey,这也令人困惑和烦恼。最后5行可能会为您节省5小时和1年的秃发。我没有尝试插入操作,所以如果您要这样做,需要仔细检查这些值,因为它们可能为0或null。

foreach(var entry in ChangeTracker.Entries<IAuditable>())
{
...

case EntityState.Deleted:

var oc = ((IObjectContextAdapter)this).ObjectContext;  //this is a DbContext
EntityKey ek = oc.ObjectStateManager.GetObjectStateEntry(entry.Entity).EntityKey;
var tablename = ek.EntitySetName;
var primaryKeyField = ek.EntityKeyValues[0].Key;     //assumes only 1 primary key
var primaryKeyValue = ek.EntityKeyValues[0].Value;

如果您没有任何ChangeTracker.Entries怎么办? - ProfK
在我的情况下,我被钩入了SaveChanges事件,并且我没有禁用更改跟踪。如果您的更改跟踪已禁用,则标记的答案应该对您有所帮助。如果您的更改跟踪未禁用,并且您已经掌握了一个实体的句柄,我认为您可以将其替换为我放置“(entry.Entity)”的第二行中。 - Bill

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接