none
Get Primary Key Properties of a Entity RRS feed

  • Question

  • Hi,

    I build a edmx and generated POCO classes with the DbContext Generator...

    My question is... 

     

    is it possible to  get the properties that are part of the primary key of the entity?

    Ex: I have a DbContext that contains a DbSet<Person>, I know that the property idPerson is part of the PK, but is there a way to get this(these) property(ies) via Reflection?

    something like .GetProperties () where P.IsPK  or .GetPrimaryKeys?

     

     

    Thank You


    Sunday, November 27, 2011 8:00 PM

Answers

  • > AS you can see, there is no attribute like [Key] etc, thats why im curios to know how the Dbset.Find(object[] keys) works, because it know if the keys match with the model...
     
     
    try using the following code:
       
    using System.Data.Metadata.Edm;
    using System.Linq;
    using System.Reflection;
    ...
    
    var mw = new MetadataWorkspace(
        new [] { "res://*/" },
        new [] { Assembly.GetExecutingAssembly() });
    var tables = mw.GetItems(DataSpace.CSpace);
    foreach(var e in tables.OfType<EntityType>())
        System.Diagnostics.Trace.WriteLine(e.Name + ": " + string.Join("\n", e.KeyMembers));
    
     

      
    • Edited by Malobukv Friday, December 9, 2011 6:41 AM
    • Marked as answer by George Domingos Saturday, December 10, 2011 5:10 PM
    Friday, December 9, 2011 6:40 AM

All replies

  • > is it possible to get the properties that are part of the primary key of the entity?


     
    you can read information from a database using the following method
     
     

    foreach(var c in IndexColumns(ds, "MyTable"))
        System.Diagnostics.Trace.WriteLine(c);
    ...
    
    public IEnumerable<string> IndexColumns(System.Data.Entity.DbContext dc, string tableName)
    {
        if (dc.Database.Exists() == false) throw new ArgumentException();
        dc.Database.Connection.Open();
        var dt = dc.Database.Connection.GetSchema("IndexColumns");
        dc.Database.Connection.Close();
        foreach (DataRow row in dt.Rows)
            if (string.Equals((string)row["table_name"], tableName, StringComparison.OrdinalIgnoreCase))
                yield return (string)row["column_name"];
    }
    

     

    Monday, November 28, 2011 10:55 AM
  • Sorry for the delay,

    The problem (if im right) is that you are query the database itself, i was thinking in something "lighter" because the key mapping is already inside the edmx right?

    The DbSet.Find() method takes PKs as params, if you provide incorrect number of columns or data-types its throws a error,
    but i think it doesnt query the db to find the PKs, its uses the information inside the edmx

    So my question is, is there a way to find whats PKs are associated with a given entity or DbSet<T> without querying the databse?

    Thank you

    Wednesday, December 7, 2011 9:52 PM
  • > i was thinking in something "lighter" because the key mapping is already inside the edmx right?



    edmx is an instruction for code generator. so at runtime there is no edmx.
    but at runtime you can find property with EdmScalarPropertyAttribute
     
    var key = FindKey<WindowsFormsApplication4.Entity1>();
    System.Diagnostics.Trace.WriteLine(key.Name);
    ...
    
    PropertyInfo FindKey<T>() where T : EntityObject
    {
        var et = typeof(T);
        var at = typeof(EdmScalarPropertyAttribute);
        var props = from p in et.GetProperties()
                          let attr = Attribute.GetCustomAttribute(p, at) as EdmScalarPropertyAttribute
                          select new { Property=p, IsKey = attr != null ? attr.EntityKeyProperty : false };
        return props.Where(p => p.IsKey == true).Select(p => p.Property).FirstOrDefault();
    }
       
        
    Thursday, December 8, 2011 4:04 AM
  • Ok, but this method is used for ObjectContext right with the EntityObject Generator? Thats because im using DbContext Code Generator so i think i cant do that for my generated classes, right? Sorry for asking again but, is there another way?

    Thursday, December 8, 2011 1:50 PM
  • > Ok, but this method is used for ObjectContext right with the EntityObject Generator? Thats because im using DbContext Code Generator so i think i cant do that for my generated classes, right?
     
     
    let me clarify. you have some following code and you want to get result "Id"?
     
     
    class Item
    {
        public int Id { get; set; }
        public string Value { get; set; }
    }
    class DataStore : DbContext
    {
        public DbSet items { get; set; }
        protected override void OnModelCreating(DbModelBuilder m)
        {
            base.OnModelCreating(m);
            m.Entity().HasKey(e => e.Id).ToTable("Items");
        }
    } 
    
      
    Thursday, December 8, 2011 2:30 PM
  • My generated code for OnModelCreating is this:
    
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                throw new UnintentionalCodeFirstException();
            }
    
    but, Yes, i want the "id" (or compound PK)
    

    Thursday, December 8, 2011 2:51 PM
  • > My generated code for OnModelCreating is this: ...
     
     
    is there any attribute over Id property? maybe [Key] or [KeyAttribute]?
    if so, try using the following code:
     
     

    using System.Linq;
    ...
    var ka = GetAttribute<MyClass, KeyAttribute>("Id");
    ...
    static public A GetAttribute<T, A>(string name)
    {
        return typeof(T)
            .GetProperty(name)
            .GetCustomAttributes(typeof(A), true)
            .OfType<A>()
            .FirstOrDefault();
    }
     
     
    • Edited by Malobukv Thursday, December 8, 2011 5:02 PM
    Thursday, December 8, 2011 5:01 PM
  • Thats the problem, there is no atribbute, i already tried to find the CustomAttributes of the class, it returns nothing...

    Ok i will post one of the generated class and the DbContext (i used the DbConext Generator)

     

    //------------------------------------------------------------------------------
    // <auto-generated>
    //    This code was generated from a template.
    //
    //    Manual changes to this file may cause unexpected behavior in your application.
    //    Manual changes to this file will be overwritten if the code is regenerated.
    // </auto-generated>
    //------------------------------------------------------------------------------
    
    using System;
    using System.Collections.Generic;
    
    namespace XamegoMuleke.EF
    {
        public partial class post
        {
            public int idPost { get; set; }
            public System.DateTime Data { get; set; }
            public string Titulo { get; set; }
            public string Resumo { get; set; }
            public string HTML { get; set; }
        }
        
    }
    
    

    //------------------------------------------------------------------------------
    // <auto-generated>
    //    This code was generated from a template.
    //
    //    Manual changes to this file may cause unexpected behavior in your application.
    //    Manual changes to this file will be overwritten if the code is regenerated.
    // </auto-generated>
    //------------------------------------------------------------------------------
    
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    
    namespace XamegoMuleke.EF
    {
        public partial class xmbdEntities : DbContext
        {
            public xmbdEntities()
                : base("name=xmbdEntities")
            {
            }
        
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                throw new UnintentionalCodeFirstException();
            }
        
            public DbSet<album> album { get; set; }
            public DbSet<albumtipo> albumtipo { get; set; }
            public DbSet<foto> foto { get; set; }
            public DbSet<fotocategoria> fotocategoria { get; set; }
            public DbSet<generomusical> generomusical { get; set; }
            public DbSet<musica> musica { get; set; }
            public DbSet<produtora> produtora { get; set; }
            public DbSet<video> video { get; set; }
            public DbSet<agenda> agenda { get; set; }
            public DbSet<post> post { get; set; }
        }
    }
    


    AS you can see, there is no attribute like [Key] etc, thats why im curios to know how the Dbset.Find(object[] keys) works, because it know if the keys match with the model...

    Friday, December 9, 2011 12:14 AM
  • > AS you can see, there is no attribute like [Key] etc, thats why im curios to know how the Dbset.Find(object[] keys) works, because it know if the keys match with the model...
     
     
    try using the following code:
       
    using System.Data.Metadata.Edm;
    using System.Linq;
    using System.Reflection;
    ...
    
    var mw = new MetadataWorkspace(
        new [] { "res://*/" },
        new [] { Assembly.GetExecutingAssembly() });
    var tables = mw.GetItems(DataSpace.CSpace);
    foreach(var e in tables.OfType<EntityType>())
        System.Diagnostics.Trace.WriteLine(e.Name + ": " + string.Join("\n", e.KeyMembers));
    
     

      
    • Edited by Malobukv Friday, December 9, 2011 6:41 AM
    • Marked as answer by George Domingos Saturday, December 10, 2011 5:10 PM
    Friday, December 9, 2011 6:40 AM
  • Now you did it!

    Marvelous!

    Thats exaclty what i wanted, i only changed the assembly because it wasnt the current...

    i was playing debugging this type....

    The only thing i dindt discover is  how can i know if the property has AutoIncrement (i.e: idPost)? maybe facets?

     

    Thank you


    Saturday, December 10, 2011 5:10 PM