Entity Framework 4: How to Find the Primary Key

Entity Framework 4: How to find the primary key?

So I was finally able to find out how to get this to work. I wish I hadn't lost the link to the blog I read last night as I didn't write the code.

public T GetByPrimaryKey<T>(int id) where T : class
{
return (T)_db.GetObjectByKey(new EntityKey(_db.DefaultContainerName + "." + this.GetEntityName<T>(), GetPrimaryKeyInfo<T>().Name, id));
}

string GetEntityName<T>()
{
string name = typeof(T).Name;
if (name.ToLower() == "person")
return "People";
else if (name.Substring(name.Length - 1, 1).ToLower() == "y")
return name.Remove(name.Length - 1, 1) + "ies";
else if (name.Substring(name.Length - 1, 1).ToLower() == "s")
return name + "es";
else
return name + "s";
}

private PropertyInfo GetPrimaryKeyInfo<T>()
{
PropertyInfo[] properties = typeof(T).GetProperties();
foreach (PropertyInfo pI in properties)
{
System.Object[] attributes = pI.GetCustomAttributes(true);
foreach (object attribute in attributes)
{
if (attribute is EdmScalarPropertyAttribute)
{
if ((attribute as EdmScalarPropertyAttribute).EntityKeyProperty == true)
return pI;
}
else if (attribute is ColumnAttribute)
{

if ((attribute as ColumnAttribute).IsPrimaryKey == true)
return pI;
}
}
}
return null;
}

I hope this helps someone else. All I can say is that it should be a little clearer on how to do this.

How to get primary key in Entity Framework for a new entry and set FK Relationship

It is my understanding that FK constraints are managed within EF, so long as they are configured in the DB.

If in your EF model the Referral is a child of Company then there should be a referrals collection accessible from the Company object instance.

UPDATE
I just built a simple sample MVC Proj, 2x SQL tables (Referrals and Company FK on CompanyId) 4 x Companies, 4th being OTHER, built an EF model with Reverse POCO for speed, added a Controller with scaffolding and views and modified my controller to the below. (I just insert the date time rather than tempCompanyName. The syntax generated here is more like that in the answer by @ashin, but it works for me.

    [HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ReferralId,CompanyId")] Referral referral)
{
if (ModelState.IsValid)
{
if (referral.CompanyId == 4)
{
var f = new Company() { Name = DateTime.Now.ToString() };
referral.Company = f;
}
db.Referrals.Add(referral);
db.SaveChanges();
return RedirectToAction("Index");
}

ViewBag.CompanyId = new SelectList(db.Companies, "CompanyId", "Name", referral.CompanyId);
return View(referral);
}

My Company model does instanciate a new Referrals Collection

    public Company()
{
Referrals = new System.Collections.Generic.List<Referral>();
}

How to get the Primary Key(s) in Entity Framework 4.1, i.e. using DbContext

You cannot use DbContext for that - DbContext API is just dumb wrapper with only most needed functionality. For everything more complex you must convert DbContext back to ObjectContext and use it. Try something like this:

Extract key names:

public static string[] GetEntityKeyNames<TEntity>(this DbContext context) where TEntity : class
{
if (context == null)
throw new ArgumentNullException("context");

var set = ((IObjectContextAdapter)context).ObjectContext.CreateObjectSet<TEntity>();
var entitySet = set.EntitySet;
return entitySet.ElementType.KeyMembers.Select(k => k.Name).ToArray();
}

Here's a method that will extract the key values of an entity:

public static IEnumerable<object> GetEntityKeys<TEntity>(this DbContext context, TEntity entity)
where TEntity : class
{
if (context == null)
throw new NullReferenceException("context");

var type = typeof(TEntity);

var set = ((IObjectContextAdapter)context).ObjectContext.CreateObjectSet<TEntity>();
var entitySet = set.EntitySet;
var keys = entitySet.ElementType.KeyMembers;
var props = keys.Select(k => type.GetProperty(k.Name));
return props.Select(p => p.GetValue(entity));
}

Entity Framework 4 getting primary key ID for inserted record

After you have inserted the entity it should have been updated so that the property that maps to the primary key in the database has the new PK value.

Entity Framework code first. Find primary key

You can ask mapping metadata to get names of key properties (there can be more then one):

ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
ObjectSet<YourEntity> set = objectContext.CreateObjectSet<YourEntity>();
IEnumerable<string> keyNames = set.EntitySet.ElementType
.KeyMembers
.Select(k => k.Name);

Once you have key names you can use reflection to access their values.

As you can see the approach reverts back to ObjectContext API because DbContext API is only for simple scenarios where you don't bother with such details like mapping metadata.

How to get primary key value with Entity Framework Core

I also faced with similar problem and found the following solution

// Entity Framework Core
public virtual int GetKey<T>(T entity)
{
var keyName = Context.Model.FindEntityType(typeof (T)).FindPrimaryKey().Properties
.Select(x => x.Name).Single();

return (int)entity.GetType().GetProperty(keyName).GetValue(entity, null);
}

Determine Primary Keys of an Entity using the Context in Entity Framework 4.0

Updated my T4 template to add the following:

<#  if(ef.IsKey(edmProperty))
{
#>
[EdmScalarPropertyAttribute(EntityKeyProperty=<#=code.CreateLiteral(true)#>)]
<#
}
#>

Then used reflection to find the EntityKeys.

Net Core: Find Primary Key of Entity Framework Core and Reflection

Expanding on suggestions from comments, you can instantiate the context in your code and invoke all EF model inspection APIs as outlined in Ivan's answer like so:

var assembly = Assembly.LoadFrom(@"C:\OnlineShoppingStore\bin\Debug\netcoreapp2.2\OnlineShoppingStore.dll");
var contextType = assembly.GetTypes().First(d => d.Name == "OnlineStoreDbContext");
var ctx = Activator.CreateInstance(contextType) as DbContext; // instantiate your context. this will effectively build your model, so you must have all required EF references in your project
var p = ctx.Model.FindEntityType(assembly.GetTypes().First(d => d.Name == "Product")); // get the type from loaded assembly
//var p = ctx.Model.FindEntityType("OnlineStoreDbContext.Product"); // querying model by type name also works, but you'd need to correctly qualify your type names
var pk = p.FindPrimaryKey().Properties.First().Name; // your PK property name as built by EF model

UPD: Forget thought experiments, it clearly is confusing.
The method above does not require you to reference your other projects and requires no prior knowledge of types except for string names (which you have as it seems).
When you instantiate your db context, the base class constructor in EF will process all your custom overrides and will return you a fully built model (i.e. all properties will be accounted for). Again, no reference will be required as long as you only use EF metadata API (which is available on base DBContext class). Hopefully that clarifies.

UPD2: following up on my IL Emit idea in comments. See the implementation and a bit more background in my blog. This enabled me to eliminate the exception (still have to have at least one DB Provider available though).



Related Topics



Leave a reply



Submit