Entity Framework 4 - Username and Email columns unique problem - c#

I have a User entity in my entity model:
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.Email == 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
}
}
}

Related

Foreign keys updating on creation but not on edit

In my application, users are able to be assigned roles. In the setup page for this, I have the following code:
foreach (string userRole in roleArray)
{
OrganizationRole orgRole = signedUpOrg.Roles.FirstOrDefault(target => target.Name == userRole && target.OrganizationId == signedUpOrg.OrganizationId);
if (orgRole != null)
{
OrganizationUser_OrganizationRole existingUserRole = orgRole.OrganizationUser_OrganizationRole.FirstOrDefault(target => target.Organization_User.User.UserId == orgUser.User.UserId &&
target.OrganizationRole.Name == userRole &&
target.OrganizationRole.OrganizationId == signedUpOrg.OrganizationId);
if (existingUserRole == null || orgUser.User.UserId == 0) // new user role to new users or existing users with new roles
{
orgRole.OrganizationUser_OrganizationRole.Add(new OrganizationUser_OrganizationRole
{
Organization_User = orgUser,
OrganizationRole = orgRole
});
}
}
}
With this, we are able to cycle through the roles which are to be assigned and save them in the database. This works perfectly fine on creating the user and their roles, but on editing there is no change. The code seems to be hit at all the crucial points with the correct data (roles, etc) but there is no reflection in the database or on the front end.
This code is in a method called SaveUsers in a class called CommonUtilities and is called in an AdministrationController with the following code:
CommonUtilities.SaveUsers(viewModel);
Can anyone possibly think of any reasons as to why this would work correctly on creation but not while editing? Many thanks in advance and I will be more than willing ot clarifiy on any points.
A similar issue drove me to choose NHibernate over EF as it can update children and grandchildren collections (probably even deeper levels but I have not tried that). Adjusting ObjectState like the answers referred to by #JhonatasKleinkauff seemed the only answer in EF but was not satisfactory in our case. This seems to only happen when you disconnect from the ObjectContext between retrieval and saving the parent object.

A generic way to save an entity in Entity Framework

I am trying to write a GenericEFRepository which will be used by other Repositories. I have a Save method as below.
public virtual void Save(T entity) // where T : class, IEntity, new() And IEntity enforces long Id { get; set; }
{
var entry = _dbContext.Entry(entity);
if (entry.State != EntityState.Detached)
return; // context already knows about entity, don't do anything
if (entity.Id < 1)
{
_dbSet.Add(entity);
return;
}
var attachedEntity = _dbSet.Local.SingleOrDefault(e => e.Id == entity.Id);
if (attachedEntity != null)
_dbContext.Entry(attachedEntity).State = EntityState.Detached;
entry.State = EntityState.Modified;
}
You can find the problem in comments of below code
using (var uow = ObjectFactory.GetInstance<IUnitOfWork>()) // uow is implemented like EFUnitOfWork which gives the DbContext instance to repositories in GetRepository
{
var userRepo = uow.GetRepository<IUserRepository>();
var user = userRepo.Get(1);
user.Name += " Updated";
userRepo.Save(user);
uow.Save(); // OK only the Name of User is Updated
}
using (var uow = ObjectFactory.GetInstance<IUnitOfWork>())
{
var userRepo = uow.GetRepository<IUserRepository>();
var user = new User
{
Id = 1,
Name = "Brand New Name"
};
userRepo.Save(user);
uow.Save();
// NOT OK
// All fields (Name, Surname, BirthDate etc.) in User are updated
// which causes unassigned fields to be cleared on db
}
The only solution I can think of is creating Entities via repository like userRepo.CreateEntity(id: 1) and repository will return an Entity which is attached to DbContext. But this seems error prone, still any developer may create an entity using new keyword.
What are your solution suggestions about this particular problem?
Note: I already know about cons and pros of using a GenericRepository and an IEntity interface. So, "Don't use a GenericRepository, don't use an IEntity, don't put a long Id in every Entity, don't do what you are trying to do" comments will not help.
Yes it is error prone but simply that is the problem with EF and repositories. You must either create entity and attach it before you set any data you want to update (Name in your case) or you must set modified state for each property you want to persist instead of whole entity (as you can imagine again developer can forget to do that).
The first solution leads to special method on your repository doing just this:
public T Create(long id) {
T entity = _dbContext.Set<T>().Create();
entity.Id = id;
_dbContext.Set<T>().Attach(entity);
return entity;
}
The second solution needs something like
public void Save(T entity, params Expression<Func<T, TProperty>>[] properties) {
...
_dbContext.Set<T>().Attach(entity);
if (properties.Length > 0) {
foreach (var propertyAccessor in properties) {
_dbContext.Entry(entity).Property(propertyAccessor).IsModified = true;
}
} else {
_dbContext.Entry(entity).State = EntityState.Modified;
}
}
and you will call it like:
userRepository(user, u => u.Name);
This is kind of a fundamental problem of this approach because you expect the repository to magically know which fields you changed and which ones you didn't. Using null as a signal for "unchanged" does not work in case null is a valid value.
You'd need to tell the repository which fields you want to have written, for example sending a string[] with the field names. Or one bool for each field. I do not think this is a good solution.
Maybe you can invert the control flow like this:
var entity = repo.Get(1);
entity.Name += "x";
repo.SaveChanges();
That would allow change tracking to work. It is closer to how EF wants to be used.
Alternative:
var entity = repo.Get(1);
entity.Name += "x";
repo.Save(entity);
While the other two answers provide good insight into how perhaps you can avoid this issue I think its worth pointing out a couple of things.
What you are trying to do (ie a proxy entity update) is extremely EF-centeric and IMO actually doesn't make sense outside of the EF context and hence it doesnt make sense that a generic repository would be expected to behave in this way.
You actually haven't even gotten the flow quite right for EF, if you attach an object with a few fields already set EF will conciser what you told it to be the current DB state unless you modify a value or set a modified flag. To do what you are attempting without a select you would normally attach an object without the name and then set the name after attaching the ID object
Your approach is normally used for performance reasons, I would suggest that by abstracting over the top of an existing framework you are almost always going to suffer some logical performance degradation. If this is a big deal maybe you shouldn't be using a repository? The more you add to your repository to cater to performance concerns the more complex and restrictive it becomes and the harder it gets to provide more than one implementation.
All that being said I do think you can handle this particular case in a generic situation.
This is one possible way you could do it
public void UpdateProperty(Expression<Func<T,bool>> selector, FunctionToSetAProperty setter/*not quite sure of the correct syntax off the top of my head*/)
{
// look in local graph for T and see if you have an already attached version
// if not attach it with your selector value set
// set the property of the setter
}
Hope this makes some sense, I'm not by my dev box atm so I cant really do a working sample.
I think this is a better approach for a generic repository as it allows you to implement this same behavior in multiple different ways, the abovc may work for EF but there will be different methods if you have an in memory repository (for example). This approach allows you to implement different implementations that fulfill the intent rather than restrict your repository to only act like EF.

Multiple requirements of a query

not certain how to word this but here goes. I'm using linq to write the service layer for a server. I've already got my database setup and I've inherited classes from that using an Entity layer (which will be replaced with a WCF layer to correctly make use of JSON - a software requirement for this project). I am currently writing a method called "JoinCalendar" ( a major part of the application) where a I want to certify that a user is valid to join the calendar.
Here's the code for startes
public bool JoinCalendar(int famID, string email)
{
using (FamilySchedulerEntities db = new FamilySchedulerEntities())
{
var checkUser = (from u in db.Users
where u.familyID.Equals(famID) && !u.emailAddress.Equals(email, StringComparison.InvariantCultureIgnoreCase)
select u).FirstOrDefault();
if( checkuser != null){ return false}
else
{
//stuff
return true;
}
The aim of this method is take the familyID (the Identity field of a group of users) of the calendar the user is trying join and that users emailaddress (the unique ID for each user). I want to perform two different checks from that query.
Firstly: I want to check that the familyID is a valid one (ie. make sure the familyID is an actual value stored on the database)
Secondly: Check that email address of the user does not match a user who is registered to any family
Thirdly: Can I use the "!" operator in a linq query oris it bad practise/etiquette
kind regards,
Simon Johnson
PS. Only been using linq (and in fact writing a database application) for less than a week so please keep this newbie friendly. Ideally I need a super elegenat solution because the client to this server may be connected using a cellular (ie. not wifi) connection and I need to keep data transmission to an absolute minimum. If the best solution is hard then please explain it sloooow
Your two requirements could be expressed as:
bool familyExists = db.Users.Any(u => u.familyID == famID);
bool emailTakenAlready = db.Users.Any(u => u.emailAddress == email);
These seem to be independent requirements, so you can do separate queries for them.
You can certainly use a logical not (!) in Linq queries where it makes sense, it's just a matter of personal style.
You can simplify it like this:
public bool JoinCalendar(int famID, string email)
{
using (var db = new DataContext())
{
var exists = db.Users.Any(u => u.familyID == famID && u.emailAddress != email);
if (exists)
{
return false;
}
//stuff
return true;
}
}
It should also be most efficient as that query can be optimized on by the database.

EF4.1 DBContext: Insert/update in one Save() function without identity PK

I have a streets table, which has a combo of two string columns acting as the PK, being postalcode and streetcode.
With EF4.1 and DBContext, I'd like to write a single "Save" method than takes a street (coming in in an unattached state), checks if it already exists in the database. If it does, it issues an UPDATE, and if it doesn't, it issues an INSERT.
FYI, the application that saves these streets, is reading them from a textfile and saves them (there a few tens of thousands of these "streetlines" in that file).
What I've come up with for now is:
public void Save(Street street)
{
var existingStreet = (
from s in streetContext.Streets
where s.PostalCode.Equals(street.PostalCode)
&& s.StreetCode.Equals(street.StreetCode)
select s
).FirstOrDefault();
if (existingStreet != null)
this.streetContext.Entry(street).State = System.Data.EntityState.Modified;
else
this.streetContext.Entry(street).State = System.Data.EntityState.Added;
this.streetContext.SaveChanges();
}
Is this good practice ? How about performance here ? Cause for every street it first does a roundtrip to the db to see if it exists.
Wouldn't it be better performance-wise to try to insert the street (state = added), and catch any PK violations ? In the catch block, I can then change the state to modified and call SaveChanges() again. Or would that not be a good practice ?
Any suggestions ?
Thanks
Select all the streets then make a for each loop that compares and change states. After the loop is done call saveChanges. This way you only make a few calls to the db instead of several thousends
Thanks for the replies but none were really satisfying, so I did some more research and rewrote the method like this, which satisfies my need.
ps: renamed the method to Import() because I find that a more appropriate name for a method that is used for (bulk) importing entities from an outside source (like a textfile in my case)
ps2: I know it's not really best practice to catch an exception and let it die silently by not doing anything with it, but I don't have the need to do anything with it in my particular case. It just serves as a method to find out that the row already exists in the database.
public void Import(Street street)
{
try
{
this.streetContext.Entry(street).State = System.Data.EntityState.Added;
this.streetContext.SaveChanges();
}
catch (System.Data.Entity.Infrastructure.DbUpdateException dbUex)
{
this.streetContext.Entry(street).State = System.Data.EntityState.Modified;
this.streetContext.SaveChanges();
}
finally
{
((IObjectContextAdapter)this.streetContext).ObjectContext.Detach(street);
}
}
Your code must result in exception if street already exists in the database because you will load it from the context and after that you will try to attach another instance with the same primary key to the same context instance.
If you really have to do this use this code instead:
public void Save(Street street)
{
string postalCode = street.PostalCode;
string streetCode = steet.StreetCode;
bool existingStreet = streetContext.Streets.Any(s =>
s.PostalCode == postalCode
&& s.StreetCode = steetCode);
if (existingStreet)
streetContext.Entry(street).State = System.Data.EntityState.Modified;
else
streetContext.Entry(street).State = System.Data.EntityState.Added;
streetContext.SaveChanges();
}
Anyway it is still not reliable solution in highly concurrent system because other thread can insert the same street between you check and subsequent insert.

C# - Entity Framework - Understanding some basics

Model #1 - This model sits in a database on our Dev Server.
Model #1 http://content.screencast.com/users/Keith.Barrows/folders/Jing/media/bdb2b000-6e60-4af0-a7a1-2bb6b05d8bc1/Model1.png
Model #2 - This model sits in a database on our Prod Server and is updated each day by automatic feeds. alt text http://content.screencast.com/users/Keith.Barrows/folders/Jing/media/4260259f-bce6-43d5-9d2a-017bd9a980d4/Model2.png
I have written what should be some simple code to sync my feed (Model #2) into my working DB (Model #1). Please note this is prototype code and the models may not be as pretty as they should. Also, the entry into Model #1 for the feed link data (mainly ClientID) is a manual process at this point which is why I am writing this simple sync method.
private void SyncFeeds()
{
var sourceList = from a in _dbFeed.Auto where a.Active == true select a;
foreach (RivWorks.Model.NegotiationAutos.Auto source in sourceList)
{
var targetList = from a in _dbRiv.Product where a.alternateProductID == source.AutoID select a;
if (targetList.Count() > 0)
{
// UPDATE...
try
{
var product = targetList.First();
product.alternateProductID = source.AutoID;
product.isFromFeed = true;
product.isDeleted = false;
product.SKU = source.StockNumber;
_dbRiv.SaveChanges();
}
catch (Exception ex)
{
string m = ex.Message;
}
}
else
{
// INSERT...
try
{
long clientID = source.Client.ClientID;
var companyDetail = (from a in _dbRiv.AutoNegotiationDetails where a.ClientID == clientID select a).First();
var company = companyDetail.Company;
switch (companyDetail.FeedSourceTable.ToUpper())
{
case "AUTO":
var product = new RivWorks.Model.Negotiation.Product();
product.alternateProductID = source.AutoID;
product.isFromFeed = true;
product.isDeleted = false;
product.SKU = source.StockNumber;
company.Product.Add(product);
break;
}
_dbRiv.SaveChanges();
}
catch (Exception ex)
{
string m = ex.Message;
}
}
}
}
Now for the questions:
In Model #2, the class structure for Auto is missing ClientID (see red circled area). Now, everything I have learned, EF creates a child class of Client and I should be able to find the ClientID in the child class. Yet, when I run my code, source.Client is a NULL object. Am I expecting something that EF does not do? Is there a way to populate the child class correctly?
Why does EF hide the child entity ID (ClientID in this case) in the parent table? Is there any way to expose it?
What else sticks out like the proverbial sore thumb?
TIA
1) The reason you are seeing a null for source.Client is because related objects are not loaded until you request them, or they are otherwise loaded into the object context. The following will load them explicitly:
if (!source.ClientReference.IsLoaded)
{
source.ClientReference.Load();
}
However, this is sub-optimal when you have a list of more than one record, as it sends one database query per Load() call. A better alternative is to the Include() method in your initial query, to instruct the ORM to load the related entities you are interested in, so:
var sourceList = from a in _dbFeed.Auto .Include("Client") where a.Active == true select a;
An alternative third method is to use something call relationship fix-up, where if, in your example for instance, the related clients had been queried previously, they would still be in your object context. For example:
var clients = (from a in _dbFeed.Client select a).ToList();
The EF will then 'fix-up' the relationships so source.Client would not be null. Obviously this is only something you would do if you required a list of all clients for synching, so is not relevant for your specific example.
Always remember that objects are never loaded into the EF unless you request them!
2) The first version of the EF deliberately does not map foreign key fields to observable fields or properties. This is a good rundown on the matter. In EF4.0, I understand foreign keys will be exposed due to popular demand.
3) One issue you may run into is the number of database queries requesting Products or AutoNegotiationContacts may generate. As an alternative, consider loading them in bulk or with a join on your initial query.
It's also seen as good practice to use an object context for one 'operation', then dispose of it, rather than persisting them across requests. There is very little overhead in initialising one, so one object context per SychFeeds() is more appropriate. ObjectContext implements IDisposable, so you can instantiate it in a using block and wrap the method's contents in that, to ensure everything is cleaned up correctly once your changes are submitted.

Categories

Resources