ObjectContext.CreateObject<T>: Create ComplexObject - entity-framework

Could someone please explain the following:
I have the following code that creates an instance of a type specified:
MethodInfo methodInfo = this._dbContext.GetType().GetMethod("CreateObject").MakeGenericMethod(instanceType);
object invokedObject = methodInfo.Invoke(this._dbContext, null);
Where the _dbContext in my Entity Model.
When I try to create an instance of the following class all is happy and it works:
public partial class User : EntityObject
{
....
}
But when I try the same within the following class - I receive an error:
The member with identity 'MyNamespace.Account' does not exist in the metadata collection.
public partial class Account : ComplexObject
{
....
}
Could someone please explain why I'm able to create an instance / object of an EntityObject but not a ComplexObject ?
Many thanks!!
[UPDATE]
public ObjectSet<User> Users
{
get
{
if ((_Users == null))
{
_Users = base.CreateObjectSet<User>("Users");
}
return _Users;
}
}
private ObjectSet<User> _Users;

There are actually 2 problems:
As noted in your updated question, your context doesn't contain reference to Account, you need to add it before requesting it (using the 'CreateObject' method) from the context:
public ObjectSet<Account> Accounts
{
get
{
if ((_Accounts == null))
{
_Accounts = base.CreateObjectSet<Account>("Accounts");
}
return _Accounts;
}
}
private ObjectSet<Account> _Accounts;
Since your Account is a ComplexType i don't think you'll be able to use it as an ObjectSet<>, since ComplexType does not have an Identity and can only be used as a part of a parent Entity.

Related

generalize dbcontext AddOrUpdate

My code :
public class BaseController
{
public object AddUpdate(object obj)
{
using (var db = new StoreModel())
{
string nameObj = obj.ToString().Substring(obj.ToString().LastIndexOf(".") + 1);
var property = db.GetType().GetProperty(nameObj);
((DbSet<CrmTicket>)property.GetValue(db)).AddOrUpdate((CrmTicket)obj);
db.SaveChanges();
return obj;
}
}
}
I would like generalize AddOrUpdate.
This code work but it's not generic, you can see CrmTicket.
I can not put a Type in his place.
((DbSet<obj.GetType()>)property.GetValue(db)).AddOrUpdate((obj.GetType())obj);
Could you help me ?
Thank you.
You could simply use generics. There are multiple ways of doing this pretty easily. Here's one way:
public class BaseController
{
protected T AddOrUpdate<T>(T obj) where T : BaseEntity
{
if (obj == null) throw new ArgumentNullException(nameof(obj));
using (StoreModel context = new StoreModel())
{
T entity = context.Set<T>().Find(obj.Id);
// the entity doesn't exists yet, so we add it
if (entity == null)
{
context.Set<T>().Add(entity);
}
// the entity exists, so we must update it
else
{
// do you update logic, like : entity.MyString = obj.MyString
// ...
// Note : there is no need to attach the entity because the Find method has already done it.
}
// Everything is done.
context.SaveChanges();
}
return obj;
}
}
// This is your base class for all entity.
// If you want to use generics and have an AddOrUpdate method,
// you must have something to rely on where you want to check if the object you want to insert is already in Db.
public class BaseEntity
{
public int Id { get; set; } // you should configure this as an Primary Key with Identity
}
But I think this is not a good idea... With that kind of considerations, you should look at repositories: http://www.tugberkugurlu.com/archive/generic-repository-pattern-entity-framework-asp-net-mvc-and-unit-testing-triangle

Angular/Breeze: how to save the data in BreezeController to database directly

This is my breezeController using EF repository:
[BreezeController]
public class BreezeController : ApiController
{
private readonly MyRepository _repository;
public BreezeController()
{
_repository = new MyRepository(User);
}
[HttpPost]
[ValidateHttpAntiForgeryToken]
public SaveResult SaveChanges(JObject saveBundle)
{
return _repository.SaveChanges(saveBundle);
}
[HttpGet]
public IQueryable<Compound> Compounds(int id)
{
var compounds = new List<Compound>();
compounds.add(new Compound() { Name = "cmp1" });
compounds.add(new Compound() { Name = "cmp2" });
compounds.add(new Compound() { Name = "cmp3" });
// Save compounds to database
return compounds.AsQueryable();
}
}
I'd like to save the compounds created here to database before returning. Should I call SaveChanges? How?
UPDATE:
I tried to bring the objects to client and save. However, I can't seem to use those objects directly as:
cs.compound = compound;
manager.saveChanges();
Because I'm getting this error "Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries". How can I get around this error? I believe I just missed a little tweak.
Instead, I had to create entity as usual, and assign properties one by one like
cs.compound = manager.createEntity("Compound");
cs.compound.name = compound.name;
...
manager.saveChanges();
This is quite cumbersome because I have a lot of properties and nested objects.
So, how can I use the objects created on server to save directly?
I don't have an idea of how you declared the dbContext inside the repository.
Let's say you have it declared this way :
public MyDBContext { get { return _contextProvider.Context; } }
Then you can add the _repository.MyDBContext.SaveChanges();
right before the line
return compounds.AsQueryable();

How to create generic EF Insert method?

I'd like to create a generic C# class with a method that will add a row to a database using Entity Framework.
I have one table called Address. I've written the following code to add an address to the database:
public class AddressExchange
{
public int Insert(Address address)
{
using (var db = new DemoWebEntities())
{
//db.AddObject("Address", address);
db.Addresses.AddObject(address);
db.SaveChanges();
return address.Id;
}
}
}
I would like to write a generic class that will perform this operation for any entity in my EDMX. I think that it should look something like this:
public class EntityExchange<T, KeyType>
{
public KeyType Insert(T t)
{
using (var db = new DemoWebEntities())
{
// The entity set name might be wrong.
db.AddObject(typeof(T).Name, t);
// EF doesn't know what the primary key is.
return t.Id;
}
}
}
I think it may be possible to use the AddObject method to add the object to the database, but the entityset name is not necessarily the same as the type name, especially if it has been pluralized!
I also want to return the primary key to the caller, but I don't know how to tell which field contains the primary key.
I have a generic InsertOrUpdate method in a generic repository that also ensures proxies are created. (Proxies are required to support lazy loading and if you create an entity using "new", then proxies are not created). See the question here
public class RepositoryBase<T> : IRepository<T> where T : ModelBase
{
public virtual T InsertOrUpdate(T e)
{
DbSet<T> dbSet = context.Set<T>();
//Generate a proxy type to support lazy loading
T instance = dbSet.Create();
DbEntityEntry<T> entry;
if (e.GetType().Equals(instance.GetType()))
{
//The entity being added is already a proxy type that
//supports lazy loading just get the context entry
entry = context.Entry(e);
}
else
{
//The entity being added has been created using the "new" operator.
//Attach the proxy
//Need to set the ID before attaching or we get
//The property 'ID' is part of the object's key
//information and cannot be modified when we call SetValues
instance.ID = e.ID;
entry = context.Entry(instance);
dbSet.Attach(instance);
//and set it's values to those of the entity
entry.CurrentValues.SetValues(e);
e = instance;
}
entry.State = e.ID == default(int) ?
EntityState.Added :
EntityState.Modified;
return e;
}
}
public abstract class ModelBase
{
public int ID { get; set; }
}
Note that all the models inherit ModelBase so that handles the ID issue and I return the entity rather than just the ID. That is probably not strictly necessary since a reference to the entity is passed in and EF performs fixup on the ID anyway so you can always access it from the refernce passed in.
This might be reliant on a particular version on Entity framework however this is how I do it
public void Create(T entity)
{
using (var db = new DemoWebEntities())
{
db.Set<T>().Add(entity);
}
}
For the primary key issue, can you use partial classes to make your entities implement an interface, something like this:
public interface IEntity
{
Guid PrimaryKey { get; }
}
Your entity classes would then return the appropriate value:
public partial class EntityType : IEntity
{
public Guid PrimaryKey
{
get
{
return this.WhateverId; // Return the primary key
}
}
}
Then, constrain your method to only accept IEntity:
public class EntityExchange<T, KeyType> where T : IEntity
And finally return the primary key after the insert:
return t.PrimaryKey;
May be it can help you.
public T Add(T model)
{
using (BigConceptEntities entity = new BigConceptEntities())
{
entity.Set<T>().Add(model);
entity.SaveChanges();
return model;
}
}

How to Create a custom validation for my entities

I would like to know if this is possible to create a custom validation for my User Entity.
I Want to verify if the username is unique.
If the user Already exist, I don't want to save it and show a warning.
I Read about Data Annotation inherits but I'm not sure of what I'm doing.
Please help.
Thanks.
Entity-Framework 4
Asp.net MVC 2
Yes it is possible, you can create your own Custom Attribute class and validate the entity. Something similar to this code,
[AttributeUsage(AttributeTargets.Class)]
public class DuplicateUserAttribute : ValidationAttribute
{
private const string _defaultErrorMessage = "user '{0}' Already exist";
public DuplicateUserAttribute ()
: base(_defaultErrorMessage)
{
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString);
}
public override bool IsValid(object value)
{
UserEntity NewUser = value as UserEntity;
//Write here logic to validate the user is already exist in database like
context.UserList.Where(u=>u.Name ==NewUser .UserName)
return ;
}
}
[DuplicateUser]
Class User
{
…
}
Also more on CustomeAttribute

How can you generically map a DbDataReader to a Castle.Windsor resolved type?

This is confusing me, so this question will probably be confusing.
I have a an application that uses implementations of an IJob interface to accomplish different tasks.
public interface IJob
{
int Id { get; set; }
string Name { get; set; }
void Run();
}
I am using the Castle.Windsor.WindsorContainer to resolve these implementations, and using the service id to help identify them.
WindsorContainer container = new WindsorContainer(new XmlInterpreter());
IJob jobToExecute = container.Resolve<IJob>("nameOfJob");
I wrote a little generic extension method that simply puts the values of SQL columns into their corresponding properties.
public static void MapTo<T>(this DbDataReader reader, ref T instance) where T : class
{
Type objectType = typeof(T);
foreach (PropertyInfo propertyInfo in objectType.GetProperties())
{
if (propertyInfo.CanWrite)
{
int ordinal = -1;
try
{
ordinal = reader.GetOrdinal(propertyInfo.Name);
object value = reader[ordinal] == DBNull.Value ? null : reader[ordinal];
propertyInfo.SetValue(instance, value, null);
}
catch (IndexOutOfRangeException ex)
{
continue;
}
}
}
}
Now, because you can't instantiate an instance of an interface, passing an IJob to this method won't work. However, in order to gain the benefits of the IoC container, I need to do everything in my repository using the IJob interface. So, I wrote with this to resolve the IJob implementation, and pass it to the MapTo method to populate the necessary properties:
public IJob GetJobById(int id)
{
string cmdTxt = "SELECT Id, Name, Description, DateStarted, ScheduledCompletion, Completed FROM Jobs WHERE Id = #id";
using (DbCommand cmd = _dataFactory.CreateCommand(cmdTxt))
{
_dataFactory.AddParam(cmd, "id", id, DbType.Int32);
using (DbDataReader rdr = cmd.ExecuteReader())
{
if (rdr.Read())
{
IJob job = _container.Resolve<IJob>("job.implementation");
rdr.MapTo<IJob>(ref job);
return job;
}
else
{
return null;
}
}
}
}
Is this an OK design decision? Do you see any problems?
Well, for one, calling methods via reflection is usually not nice... and it looks like you're using Windsor as a type dictionary, which it is not...
I would write a non-generic MapTo (which would take a Type as parameter) that operates on an already-existing instance (when you create a new instance with Activator.CreateInstance you discard the instance Windsor had resolved) and then use it from the ComponentCreatedEvent event in IKernel. Something like this:
container.Kernel.ComponentCreated += (model, instance) => {
if (model.Service == typeof(IJob)) {
// select id,name from jobs where id = model.Name
// use MapTo to fill id,name into instance
}
}