开发者

Entity Framework 4 - Username and Email columns unique problem

I have a User entity in my entity model:

Entity Framework 4 - Username and Email columns unique problem

Username and Email should be unique but for now EF4 doesn't support this.

So I wrote this code to ensure uniqueness :

public void CreateNewUser(string i_UserName, string i_Email)
{
    using (ModelContainer context = new ModelContainer())
    {
        User usr;

        usr = context.UserSet.Where(u => u.Username == i_UserName).SingleOrDefault();
        if (usr != null)
            throw new Exception("Username not unique");

        usr = context.UserSet.Where(u => u.Emai开发者_如何学编程l == i_Email).SingleOrDefault();
        if (usr != null)
            throw new Exception("Email not unique");

        context.UserSet.AddObject(new User() { Username = i_UserName, Email = i_Email });
        context.SaveChanges();                               
    }
}

If this is right approach, do I have way to automatically preform this code whenever context.UserSet.AddObject() is called? Or a more elegant way does exist?


I don't know of a more elegant way. Rather than using SingleOrDefault, I think you want something like:

bool isUniqueUserName = !context.UserSet.Any(u => u.Username == i_UserName); 

for performance. Any() stops at the first match and doesn't have to enumerate the entire sequence.


Correct way is defining Unique index in database and catching an exception. These checks in code must be much more complex then simple: say me if the user already exists. First of all this is not only problem of insert but user can also usually modify his email. Another problem is concurrency - in very corner case you can have two users inserting same records in the same time. In both threads test queries can return that user name and email are not registered but during the saving one thread will get an exception (if you have unique index in db) or duplicit record will be created. If you want to avoid it you must lock your database records and lock table for insertion (serializable transaction). Such operation can decrease throughput of your application.

Another fact is that you will do 2 additional queries before each insert and at least one query before each update.


I use the same approach. Just ensure that you have one method that insert it and you should be find. Similar to factory method pattern.


Branching off of @ysrb's answer (having a single method that does the User insert), a more foolproof solution might be to hook into the ObjectContext.SavingChanges event and do your test there if a User entity is being saved. This way you can be sure your logic always fires.

Example:

        IEnumerable<ObjectStateEntry> changes = this.ObjectStateManager.GetObjectStateEntries(EntityState.Added);
        foreach (ObjectStateEntry stateEntryEntity in changes)
        {
            if (!stateEntryEntity.IsRelationship && stateEntryEntity.Entity != null)
            {
                if (stateEntryEntity.Entity is User)
                {
                    //Do you work here
                }
            }
        }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜