none
Given up Entity Framework for this project.Nobody answered RRS feed

  • Question

  • Hi all,

    I have xmls files which contains data to be inserted into a database.

    Let's assume I have 2 entities  Customer-Orders

    I don't want to instantiate the object at design time EG

    Customer customer =new Customer();
    customer.Name="John"
    mydbContext.Customers.AddObject(customer);

    I will read the name of the class in this xml File 

    1. Get the entity
    2. Get the Properties
    3. Loop through them
    4. Set them 
    5. Commit

    This is what I have done but I am stuck

    string connectionString = ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString;
    
            using (var ctx = new Context(connectionString))
            {
                EntitySetBase entity = ctx.GetEntitySet("Customers");
               List<EdmMember> props = entity.GetProperties();
                for (int index = 0; index < props.Count; index++)
                {
                    EdmMember edmMember = props[index];
                    edmMember.SetValue(edmMember, "ValuecomingfromXmlFile", index);  //edmMember HAS NO SETVALUE HOW CAN i SET THE VALUE?
                }
    
                ctx.Attach(???); //Do I need to attach or ????
                ctx.SaveChanges();
            }
    
         public static EntitySetBase GetEntitySet(this ObjectContext context,string entityName)
        {            
    
            var container = context.MetadataWorkspace.GetEntityContainer(context.DefaultContainerName, DataSpace.CSpace);
            var entity = (container.BaseEntitySets.Where(meta => meta.ElementType.Name == entityName)).FirstOrDefault();
            return entity;
        }
       public static List<EdmMember> GetProperties(this EntitySetBase entitySet)
        {
            List<EdmMember> edmMembers = (entitySet.ElementType.Members.Select(p => p)).ToList();
            return edmMembers;
        }

    How can I do this?

    Can Anybody put me through the right direction?

    thanks



    • Edited by brixgb Saturday, June 8, 2013 5:57 AM
    Wednesday, June 5, 2013 1:32 PM

Answers

  • "Sort of works"? In my previous example you update all existing entities, that's why there was a loop involved. If you have no data, then there's nothing to update?

    To be able to add a new entity you can try the following:

    Type entityType = Type.GetType("Namespace.Customer", YourModelAssembly);
          object entityInstance = Activator.CreateInstance(entityType);
          PropertyInfo[] propertyInfos = entityType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
          foreach (var propertyInfo in propertyInfos) {
            string value = "FromXml";
            propertyInfo.SetValue(entityInstance, Convert.ChangeType(value, propertyInfo.PropertyType), null);
          }
          context.Entry(entityInstance).State = System.Data.EntityState.Added;
          context.SaveChanges();

    • Marked as answer by brixgb Friday, June 14, 2013 10:26 AM
    Thursday, June 13, 2013 1:49 PM

All replies

  • Hi brixgb,

    Attach method is used for the entities which already exist in the database. For example if you create a new instance of your entity and you are sure it exists in the database, the entity's state is detached and you can use the Attach method.

    If the entity is queried from the entity collection in the context, the entity's state is unchanged that you don't need to call Attach method.

    If there are any exceptions, please feel free to post here.

    Best regards,


    Chester Hong
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, June 10, 2013 2:45 AM
    Moderator
  • Thanks for your reply.

    Finally somebody answered!!!

    All I am trying to do is create the entities at runtime and save them.

    I really appreaciate your time to answer but still does NOT answer my question.

    How can I add an object at runtime (using database first).

    I already have a database but cannot create the entities at designtime.

    Is there anywhere an example of creating an entity at runtime taking into account that the entities are already been generated is just a case of mapping them at run time hence me trying to read the properties of each one of them and map them

    Thanks

    Monday, June 10, 2013 8:33 AM

  • If you are asking on how to add a new customer to the database using EF and DbContext the answer is to set the state of the item to Added before calling the SaveChanges method:

    using (var context = new MyDbContext(connectionString))
    {
        Customer customer =new Customer();
        customer.Name="John"
        context.Entry(customer).State = System.Data.EntityState.Added;
        //or context.Customers.Add(customer); This will add the entire graph of objects
        context.SaveChanges();
    }

    To update the properties of an existing customer, you would simply fetch the record from the database, update the properties with values from your XML file and commit the changes by calling the SaveChanges method:

    using (var context = new Context(connectionString))
    {
        List<Customers> customers = (from c in ctx.Customers select c).ToList();
        foreach(Customer customer in customers)
        {
     customer.Name = "ValuecomingfromXmlFile";
            customer.OtherProperty = "...";
        }
        
        context.SaveChanges();
    }

    Monday, June 10, 2013 8:47 AM
  • Hi Magnus

    Thanks for your time in reply.

    Unfortunately only at run time I will know which entity I will need to save

    What my question is about is not how to save a eg a "Customer" at design time, I know that because  I pointed out in my question

    But how to dynamically populate each property of the entity given a name.
    (I have xml file which among other things contains EntityName and properties to be mapped that match the properties of the EF.Entity)


    What I need to do is:

    Given the entityName 
    GetAllProperties that belong to the entity
    Map each property at runtime EG Reflection "Property.SetValue"
    save the object .

    How do you set a property at runtime .Do you use reflection and if so how do you do "mydbContext.Customers.AddObject(customer);" using reflection?
    How do you get the metadata?

    Hope it's  clear

    Monday, June 10, 2013 11:16 AM
  • Right, try something like this then:

    Type entityType = Type.GetType("Namespace.Customer, YourModelAssembly"); DbSet<MyEntity> set = context.Set<entityType>(); foreach(T entity in set) { PropertyInfo propertyInfo = entityType.GetProperty("NameOfProperty"); string value = "ValuecomingfromXmlFile"; propertyInfo.SetValue(entity, Convert.ChangeType(value, propertyInfo.PropertyType), null); }

    context.SaveChanges();


    Monday, June 10, 2013 12:19 PM
  • Hi Magnus,

    We are getting close but still I have an issue because at runtime I cannot Set

    DBSet<MyEntity>set=ect...    I am using DatabaseFirst.

    that is why I had a method to get the entity just based on the name as string but does not seem to work.

     [Test]
            public void SaveChanges_ReadingPropsAtRunTime_IsSaved()
            {
                string connectionString = ConfigurationManager.ConnectionStrings["DBContext"].ConnectionString;
               
                using (var ctx = new DbContext(connectionString))
                {
                    EntitySetBase entity = "Customer".GetEntitySet(ctx);
                    PropertyInfo[] propertyInfos = entity.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
                    //propertyInfos returns only 2 props "buildintypeKind-ElementType
                    foreach (var propertyInfo in propertyInfos)
                    {
                        string value = "FromXml";
                        propertyInfo.SetValue(entity, Convert.ChangeType(value, propertyInfo.PropertyType), null);
                     }
    
                    ctx.SaveChanges();
                }
            }


     public static EntitySetBase GetEntitySet(this string entityName,ObjectContext context)
            {
             
                var container = context.MetadataWorkspace.GetEntityContainer(context.DefaultContainerName, DataSpace.CSpace);
                var entity = (container.BaseEntitySets.Where(meta => meta.ElementType.Name == entityName)).FirstOrDefault();
                return entity;
            }
    
            public static MetadataProperty GetProperty(this MetadataItem entitySet, string propertyName)
            {
                MetadataProperty property;
                if (entitySet == null)
                    throw new ArgumentNullException("entitySet");
                if (entitySet.MetadataProperties.TryGetValue(propertyName, false, out property))
                {
                    return property;
                }
                return null;
            }

    Any Ideas

    Many thanks


    • Edited by brixgb Monday, June 10, 2013 3:23 PM
    Monday, June 10, 2013 3:22 PM
  • It should be DbSet<entityType> set = context.Set<entityType>();
    Tuesday, June 11, 2013 7:34 AM
  • Hi Thanks for your reply.

    that sort of works but if you have no data in db it does not loop through.

    Also why do I need  a loop

    foreach(T entity in set)
    {}

    is the dbSet an entity.

    also the T for generic I have no generic there.

    Really appreciate your help.I know I keep coming up with question ,this is because I get psuedo code that gives you the idea but does not work.

    thanks

    Thursday, June 13, 2013 1:28 PM
  • "Sort of works"? In my previous example you update all existing entities, that's why there was a loop involved. If you have no data, then there's nothing to update?

    To be able to add a new entity you can try the following:

    Type entityType = Type.GetType("Namespace.Customer", YourModelAssembly);
          object entityInstance = Activator.CreateInstance(entityType);
          PropertyInfo[] propertyInfos = entityType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
          foreach (var propertyInfo in propertyInfos) {
            string value = "FromXml";
            propertyInfo.SetValue(entityInstance, Convert.ChangeType(value, propertyInfo.PropertyType), null);
          }
          context.Entry(entityInstance).State = System.Data.EntityState.Added;
          context.SaveChanges();

    • Marked as answer by brixgb Friday, June 14, 2013 10:26 AM
    Thursday, June 13, 2013 1:49 PM
  • Magnus,

    Thank you!! all works now.

    My next challenge is to find out how to write parent-child at runtime.

    What I mean is 

    As it stands I guess when I have a relationship with foreign keys "CustomerAddress" will fail to insert as cannot find the CustomerId (parent)

    I have 2 Entities related 

    1. Customer Parent
    2. CustomerAddress  child

    How do I find out when looping using reflection find the parent if any and add it to it?

    any suggestions?

    Many thanks

    Friday, June 14, 2013 10:30 AM
  • When you are adding a CustomerAddress you must set the CustomerId property to the id of an existing customer. Don't you get the relationsships between the objects through your XML file?
    Friday, June 14, 2013 10:36 AM
  • I will add the relationship.

    Are saying the following:

    When looping

    1. process customer .  All good
    2. Loop moves next
    3. Process customerAddress
    4. When It a FK ,Search the entity in memory to find a FK that matches and set it

    Is that what you mean?

    Friday, June 14, 2013 11:13 AM
  • If the addresses are coming from the XML file, how do you know the corresponding customer for each address if you don't get that information from the file? Obviously, according to the one-to-many relationsship an address cannot exist without a reference to a customer. So yes, you'll have to have a CustomerId to associate every address with.
    Friday, June 14, 2013 11:44 AM