This may be little weird, but I want to persist only the scalar properties of an object to the database. eg. let's say I have 2 tables/entities "User" and "UserOrder". "User" entity has "FirstName", "LastName", "UserOrders" (collection of "UserOrder"). Now, I get a "User" object which has some UserOrders in it. I need to persist only the scalar properties of the the "User" i.e.FirstName & LastName.
If I do context.Users.AddObject(user), it is adding "UserOrders" also to the db (which I don't want). Does creating a new "User" object and copying all the scalars in to that is my only option (or) can we explicitly tell EF to persist only the scalars even though there are other navigational properties in it?
The reason I ask is I have to persist "User" and "UserOrders" separately in 2 different steps.
Very bizarre - i'm sure you have your reasons for doing this.
You could remove the navigational properties (e.g non-scalar) from the model, so you can persist the two objects seperately.
Step 1 - Adding a User:
var user = new User { };
user.UserOrders = new UserOrders { }; // compiler error! no property exists. good!
ctx.Users.AddObject(user); // only user scalar properties added
Step 2 - Adding a UserOrder - which still needs to "relate" to a User:
var relatedUser = ctx.Users.First(); // grab the user related to this order
var userOrder = new UserOrder { UserId = relatedUser.UserId }; // explicitly set the FK
ctx.UserOrders.AddObject(userOrder); // UserOrder added with appropriate FK
That should work - i haven't tried it before, but give it a go.
Keep in mind the drawback of this approach is you will not be able to eager/lazy load UserOrders when you request a User - you will have to manually join on the FK using LINQ.
Can you explain why you need to do this in 2 separate steps? Either way, if you have a limited number of navigational properties, you could simply store in another variable & remove:
var orders = user.Orders;
user.Orders = null;
context.Users.AddObject(user);
...
context.Orders.AddObject(orders); // You might have to do these one by one
Related
I'm trying to get all the Hotfix and include all the details (associated with it) where the property Available is 1. This is my code:
public static IList<HotFix> GetAllHotFix()
{
using (Context context = new Context())
{
return context.HotFix
.Include(h => h.AssociatedPRs)
.Include(h => h.Detail.Where(d => d.Available = 1))
.ToList();
}
}
And I'm getting that error. I tried using .ThenInclude but couldn't solve it.
Inside HotFix I have:
[Required]
public virtual List<HotFixDetail> Detail { get; set; }
Although you forgot to write your class definitions, it seems that you have a HotFix class. Every HotFix has a sequence of zero or more AssociatedPRs and a sequence of zero or more Details.
Ever Detail has at least one numeric property Available.
You want all HotFixes, each with all its AssociatedPRs, and all Details that have a property Available value equal to 1 (didn't you mean that available is a Boolean?)
When using entity framework, people tend to use include to get an item with its sub-items. This is not always the most efficient method, as it gets the complete row of a table, inclusive all the properties that you do not plan to use.
For instance, if you have a one-to-many relationship, Schools with their Students, then each Student will have a foreign key to the School that this `Student attends.
So if School [10] has 1000 Students, then every Student will have a foreign key to the School with a value 10. If you use Include to fetch School [10] with its Students, then this foreign key value is also selected, and sent a 1000 times. You already know it will equal the Schools primary key value, hence it is a waste of processing power to transport this value 10 a 1001 times.
When querying data, always use Select, and Select only the properties you actually plan to use. Only use Include if you plan to update the fetched data.
Another good advice is to use plurals to describe sequences and singulars to describe one item in your sequence
Your query will be:
var result = context.HotFixes.Select(hotfix => new
{
// Select only the hotfix properties you actually plan to use:
Id = hotfix.Id,
Date = hotfix.Date,
...
AssociatedPRs = hotfix.AssociatedPRs.Select(accociatedPr => new
{
// again, select only the associatedPr properties that you plan to use
Id = associatedPr.Id,
Name = associatedPr.Name,
...
// foreign key not needed, you already know the value
// HotFixId = associatedPr.HotFixId
})
.ToList(),
Details = hotfix.Details
.Where(detail => detail.Available == 1)
.Select(detail => new
{
Id = detail.Id,
Description = detail.Description,
...
// not needed, you know the value:
// Available = detail.Available,
// not needed, you know the value:
// HotFixId = detail.HotFixId,
})
.ToList(),
});
I used anonymous type. You can only use it within the procedure in which the anonymous type is defined. If you need to return the fetched data, you'll need to put the selected data in a class.
return context.HotFixes.Select(hotfix => new HotFix()
{
Id = hotfix.Id,
Date = hotfix.Date,
...
AssociatedPRs = hotfix.AssociatedPRs.Select(accociatedPr => new AssociatedPr()
{
... // etc
Note: you still don't have to fill all the fields, unless your function requirement specifically states this.
It might be confusing for users of your function to not know which fields will actually be filled and which ones will not. On the other hand: when adding items to your database they are already accustomed not to fill in all fields, for instance the primary and foreign keys.
As a solution for that not all fields are filled, some developers design an extra layer: the repository layer (using the repository pattern). For this they create classes that represent the data that people want to put into storage and want to save into the storage. Usually those people are not interested in that the data is saved in a relational database, with foreign keys and stuff. So the repository classes won't have the foreign keys
The advantage of the repository pattern is, that the repository layer hides the actual structure of your storage system. It even hides that it is a relational database. It might also be in a JSON-file. If the database changes, users of the repository layer don't have to know about this, and probably don't need to change as well.
A repository pattern also makes it easier to mock the database for unit testing: since users don't know that the data is in a relational database, for the unit test you can save the date in a JSON file, or a CSV-file or whatever.
The disadvantage is that you need to write extra classes that holds the data that is to be put into the repository, or fetched from the repository.
Whether it is wise to add this extra layer or not, depends on how often you expect your database to change layout in the future, and how good your unit tests need to be.
I have the following tables represented in my Entity Framework diagram (.edmx file)
Users
- UserID
- Username
- UserGroupID
Groups
- GroupID
- GroupName
In my code, I retrieve a valid instance of the User object and I'm trying to traverse the relationship to get to the Groups table, to retrieve the GroupName, however everytime, the Groups object is null. The UserGroupID exists in the Groups table, so i'm not sure why this is.
The Visual Studio intellisense knows the relationship exists and allows me to attempt it, but at runtime, the 'Groups' instance is null.
Users users= (Users)e.Row.DataItem;
string groupName = users.Groups.GroupName;
In that case, Groups is null and i'm not sure why. What are the possible causes?
Thanks
Kevin
Looks like you are trying to access Groups from within a databound event and the Groups data was not loaded before you binded it. You most likely need to "include" Groups like below.
var users = entity.Users.include("Groups").where(x => x.UserID == 20);
You might want to read this, Entity doesn't seem to act the same as Linq-To-SQL when it comes to Lazy Loading
http://www.singingeels.com/Articles/Entity_Framework_and_Lazy_Loading.aspx
How to load related items: http://msdn.microsoft.com/en-us/library/bb896272.aspx
probably the lazy loading is disabled.
add the below line when you initialize the context
context.ContextOptions.LazyLoadingEnabled = true;
anyway you should think about what strategy you want to use to pull date from your DB
In Entity Framework, when I've mapped my tables to the corresponding entities through the designer and get to actually using them, I'll find that an entity - Thing, who has a relationship (many to one, or one to one) with another object, say, Bob, for example, would produce the following three properties on Thing:
Bob
BobId
BobReference
And were I to set BobId, and save my entity, the next time I fetch this Thing, I'll be able to navigate the Bob property without trouble. I'm curious, however, if it is possible to configure EF to allow me to navigate the property without having to immediately save.
You can do something like this: (EF 4.1)
//Has to exists a record on Bob table with Id = 1
var thing = new Thing() { BobId = 1 };
var context = new YouContext();
context.Entry(thing ).State = EntityState.Unchanged;
context.Entry(thing ).Reference(x => x.Bob).Load();
and then thing.Bob is != null
I'm playing around with NHibernate 3.0. So far things are pretty cool. I'm trying to attach an entity that wasn't detached previously:
var post = new Post(){ Id = 2 };
session.Update(post); // Thought this would work but it doesn't.
post.Title = "New Title After Update";
session.Flush();
What I'm trying to write is the following:
var post = new Post(){ Id = 2 };
session.Attach(post);
post.Title = "New Title After Update";
session.Flush(); // Sql should be something like: UPDATE Post SET Title='New Title After Update' WHERE Id=2
Is this possible so that only Title gets updated? This is currently possible in EntityFramework. I'd like to not have to load Post from the database when I just need to update a few properties. Also, I'm trying to avoid a method call that would create the object... since it's moving away from an object oriented approach in my opinion.
EDIT: I know about using transactions, I just used Flush() to make the code simple. Ok so I think we're sort of getting on the right track for what I'm trying to achieve. I'd like to be able to create an entity with a known Id using the constructor, like I have in the 2nd code block above. I don't want to have to make a call to Get<T> or Load<T> since it feels rather wrong constructing objects like this that already exist in the database. For example, in Entity Framework I can write the 2nd code example and it will "just work". It only updates the Title property.
You can session.Save() or session.SaveOrUpdate()
update
Okay, I think I see now what you are trying to do. You are trying to update a single property on a Post that was previously persisted, not a new Post, and to do that you're instantiating a new Post and giving it the Id of one in the database.
I'm not sure what you mean when you say you're trying to avoid a method call that would create the object, but the way to do this with NHibernate is this:
var post = session.Load<Post>(2);
post.Title = "New Title";
session.SaveOrUpdate(post);
In general, you should not be calling Flush() on your sessions.
The important thing to note here is the use of session.Load. Calling Load with an id in and of itself does not load the entity from the database. The entity's property values will only be loaded when/if you access them.
Of course, in this scenario, I believe that NHibernate will load the properties for the Post, (but not collections unless you've specified an eager fetch mode), and that makes sense (frankly, I don't understand why EF would not load the entity). What if the setter for your Title property does something important, like check it against the existing title, validate the title's length, check your credentials, or update another property? Simply sending an UPDATE to the database isn't sufficient.
It's possible to only update changed properties by setting dynamic-update in the mapping. However, as far as I know, it is not possible (without reverting to SQL) to perform an update without retrieving the object from the database at some point.
Use the Merge method. You have to create a new instance variable to accept the attached entity = nhibernate will not do anything else with your detached instance.
var post = new Post(){ Id = 2 };
post.Title = "New Title After Update";
// Must create a new instance to hold final attached entity
var attachedPost = session.Merge(post);
session.Update(attachedPost);
session.Flush();
// Use attachedPost after this if still needed as in session entity
That covers the "attach" functionality you are looking for, but I don't see how you are going to be able to only update the one property. if the object instance has not been populated from the database, the properties will be different. Dynamic mapping will not solve this - NHibernate sees the properties as "updated" to a bunch of nulls, empty strings.
Gotta say, you are creating a new instance but what you are actually doing is updating an existing instance. You are working directly with IDs not objects. And you are setting a single property and now have an instance potentially hanging around and doing more things but it has not enforced any invariants and may in fact bear no resemblence to the real deal other than the id property...
It all feels pretty anti-object oriented to me personally.
Problem
I got two related tables, with a foreign key that doesn't enforce FK contraints. The "child" table should be allowed to specify a "parent" key, which is either NULL or non-existing ID.
My data access is built using Linq2Sql and it generates a one-to-many relation in the model of my tables.
The problem comes in some cleanup code, which will daily look through all the changes for the last day and fix any "errors" in the data.
Example
foreach (var user in data.Users)
{
// Check if the user has a specified office, which does not exists.
if (user.OfficeId != null && user.Office == null)
{
user.OfficeId = null; // This throws exception
}
}
Exception: System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException: Operation is not valid due to the current state of the object
This is normal behavior and somewhat expected, so I tried to set the reference object instead. But how do I define an "empty" Office?
var emptyOffice = new Office();
user.Office = emptyOffice;
The above code sets the OfficeId to NULL on the user instance, but obviously it fails during update as it tries to add a new "empty" Office to the database.
Possible solution
What I'm left with is running my own SQL which does the update, though it would be nice to actually be able to do this through Linq2Sql as there are other columns on the same row I'm updating when the related "parent" is non-existing.
Notes
There are some requirements here that is important for any comments:
The database cannot be changed.
Multiple systems is dependent on the same database schema.
Can potentially change to Entity Framework, if it supports such a scenario.
Running a custom SQL is not a problem and I'll be doing that until I find a better solution.
Would like to learn and know how to do this without any special code.
My code has FKs enforced, so I haven't tested this, but have you tried explicitly setting
user.Office = null;
That should force the FK value OfficeId to null, too.
If that doesn't work, then it the following certainly should:
user.Office = new Office(); // or keep a cached dummy Office object to save time
user.Office = null;
That will force the FK reference to realize that its value has been changed and set to null.