Entity Framework 4.1: HOWTO know the next identifier assigned by Database automatically - entity-framework

I have POCO objects which their identifiers are unique and generated automatically by the database, so the problem is when you want to know for some reason which will be the next identifier that the database is going to assign to the next record you are inserting. As far as I know it is only possible after performin dbContext.SaveChanges() so I would like to know if I am right or is there a way to know the next identifier assigned by database automatically.

is there a way to know the next identifier assigned by database
automatically
Well, the next one NO. And if your code depends on it, you really need to change your design.
If you need the identifier to insert related objects, you should check some other questions because you can assign entities to eachother instead of ID's and it will be fine.

I agree with the general purport of the comments that having to know an identity value is "smelly". But on the other hand sometimes you have to live with a given design.
You can't really get the value of the next id, but you can get the value of the assigned id in time by using a TransactionScope.
using (var trans = new TransactionScope())
{
// Create new object
...
context.SaveChanges();
int id = newEntity.Id;
dependentEntity.IdString = string.Format("{0:0000000}", id);
context.SaveChanges();
trans.Complete();
}

Related

"Cannot insert explicit value for identity column in table 'x' when IDENTITY_INSERT is set to OFF" - inserting record with nested custom object

I get the error "Cannot insert explicit value for identity column in table 'UserPermission' when IDENTITY_INSERT is set to OFF" trying to insert a record as follows:
dbContext.User.Add(someUser);
dbContext.SaveChanges();
That being said, the User file has the custom class UserPermission as one of its parameters, and someUser's UserPermission is not null and has a set ID parameter. Why does this happen and is it possible to avoid getting this error without having to explicitly add a UserPermissionID foreign key parameter in my User model and setting the UserPermission parameter to null?
Thanks in advance.
This issue typically happens when deserializing entities that have related entities in the object graph then attempting to add them. UserPermission is likely an existing record that in the DB is set up with an identity PK, but EF doesn't appear to recognize that in the entity definition. (I.e. set to DatabaseGenerated(DatabaseGeneratedOption.Identity). If it had been you would most likely be seeing a different problem where a completely new duplicate UserPermission was being created.
If someUser, and it's associated someUser.UserPermission are deserialized entities then you need to do a bit of work to ensure EF is aware that UserPermission is an existing row:
void AddUser(User someUser)
{
var existingPermission = _context.UserPermissions.Local
.SingleOrDefault(x => x.UserPermissionId == someUser.UserPermission.UserPermissionId);
if (existingPermission != null)
someUser.UserPermission = existingPermission;
else
_context.Attach(someUser.UserPermission);
_context.Users.Add(someUser);
_context.SaveChanges();
}
In a nutshell, when working with detached entities that a DbContext may not be tracking, we need to check the Local state for any existing tracked instance for that ID. If we find one, we substitute the detached reference for the tracked one. If we don't find one, we attach the detached one before Adding our user.
This still isn't entirely safe because it assumes that the referenced UserPermission will exist in the database. If for any reason a non-existent UserPermission is sent in (row deleted, or fake data) you will get an exception on Save.
Passing detached entity references around can seem like a simple option at first, but you need to do this for every reference within a detached entity. If you simply call Attach without first checking, it will likely work until you come across a scenario where at runtime it doesn't work because the context happens to already be tracking an instance.

possible to return only one column using JPA

I have an Open JPA entity and it successfully connects a many-to-many relationship. Right now I successfully get the entire table, but I really only want the ID's from that tables. I plan on calling the database later to reconstruct the entities that I need (according to the flow of my program).
I need only the ID's (or one column from that table).
1) Should I try and restrict this in my entity beans, or in the stateless session beans that I will be using to call the entity beans
2) If I try and do this using JPA, how can I specify that I only get back the ID's from the table, instead of the whole table? So far looking online, I don't see a way that you can do this. So I am guessing there is no way to do this.
3) If I simply just manipulate the return values, should I create a separate class that I will be returning to the user that will return only the required id list to the user?
I could be completely wrong here, but from the looks of it, I don't think there is a simple way to do this using JPA and I will have to return a custom object instead of the entity bean to the user (this custom object would only hold the id's as opposed to the whole table as it currently does)
Any thoughts... I don't think this is really relevant, but people are always asking for code, so here you go...
#ManyToMany(fetch=FetchType.EAGER)
#JoinTable(name="QUICK_LAUNCH_DISTLIST",
joinColumns=#JoinColumn(name="QUICK_LAUNCH_ID"),
inverseJoinColumns=#JoinColumn(name="LIST_ID"))
private List<DistributionList> distributionlistList;
Currently how I get the entire collection of records. Remember I only want the id...
try
{
//int daSize = 0;
//System.out.println("Testing 1.2..3...! ");
qlList = emf.createNamedQuery("getQuickLaunch").getResultList();
}
This is how I call the Entity beans. I am thinking this is where I will have to programatically go through and create a custom object similar to the entity bean (but it just has the ID's and not the whole table, and attempt to put the id's in there somewhere.
What are your thoughts?
Thanks
I believe I just figured out the best solution to this problem.
This link would be the answer:
my other stack overflow answer post
But for the sake of those too lazy to click on the link I essentially used the #ElementCollection attribute...
#ElementCollection(fetch=FetchType.EAGER)
#CollectionTable(name="QUICK_LAUNCH_DISTLIST",joinColumns=#JoinColumn(name="QUICK_LAUNCH_ID"))
#Column(name="LIST_ID")
private List<Long> distListIDs;
That did it.
Sounds like you want something like this in your quickLaunch class:
#Transient
public List<Integer> getDistributionListIds () {
List<Integer> distributionListIds = new LinkedList<Integer>();
List<DistributionList> distributionlistList = getDistributionlistList();
if (distributionlistList != null) {
for (DistributionList distributionList : distributionlistList)
distributionListIds.add(distributionList.getId());
}
return distributionListIds;
}
I had to guess a little at the names of your getters/setters and the type of DistributionList's ID. But basically, JPA is already nicely handling all of the relationships for you, so just take the values you want from the related objects.

how to create a auto-incremented attribute in xcode managed object model

Hey, what i want to do is to make a int that will be the ID of the entity and auto increment itself whenever a new entity is added (just like a SQL identity property). Is this possible? i tried using indexed (checked on attribute) however there is no description to what indexed even does.
EDIT:
I am adding annotations to a map, when you click the pin the annotationview with a chevron shows up. Now when you click this button i would like to load an associated picture. However the only way i know how to link the picture to this button is to give the picture a unique id, and then set the button.tag to this id and then load based on the button.tag.
This kind of concept is contrary to the principles of Core Data - the idea is that you're managing sets of entities with properties, not rows in a database or other things that need to be uniqued. (If you're using the SQLite store, Core Data will create an ID for you behind the scenes, but you can't access it.)
You should probably reconsider (or at least give more details about) the problem you're trying to solve, because as it stands, Core Data will not let you autoincrement a variable.
If you absolutely must, you can manually increment on insert by having some NSNumber ID field on your entity, then every time you insert a new entity, get the existing entities sorted by that ID and limited to one result (using a NSFetchRequest with various options), grab that entity's ID, add one, and set it as the new entity's ID. It's a lot of work, though, and probably error-prone.
Edit: Based on the extra information, I'd say rather than trying to autoincrement an ID yourself, find some other guaranteed-unique property of the annotation and either use that directly or write a hash function that uses it to generate your unique ID. For example, use the latitude & longitude to build a single integer that uniquely represents that point within your system. Other than that, there's no way around having to increment the ID yourself.
I agree that this is a sticky problem - I haven't ever come across something like this in Core Data before, and I can see where autoincrementing might be useful :)
This is the simplest way, but takes some effort.
Create an "index" attribute in your Entity. Make it a String
When you create a new one, generate a GUID using CFUUIDCreate() and CFUUIDCreateString()
Assign the GUID to the "index" attribute
Voila, you now have a nearly-perfect unique ID, ready to use for caching locally and using as needed
CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
CFStringRef uuidStringRef = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
NSString* guidString = [NSString stringWithString:(__bridge NSString*)uuidStringRef];

Adding & Removing Associations - Entity Framework

I'm trying to get to grips with EF this week and I'm going ok so far but I've just hit my first major snag. I have a table of items and a table of categories. Each item can be 'tagged' with many categories so I created a link table. Two columns, one the primary ID of the item, the other the primary ID of the category. I added some data manually to the DB and I can query it all fine through EF in my code.
Now I want to 'tag' a new item with one of the existing categories. I have the category ID to add and the ID of the Item. I load both as entities using linq and then try the following.
int categoryToAddId = Convert.ToInt32(ddlCategoriesRemaining.SelectedValue);
var categoryToAdd = db.CollectionCategorySet.First(x => x.ID == categoryToAddId);
currentCollectionItem.Categories.Add(categoryToAdd);
db.SaveChanges();
But I get "Unable to update the EntitySet 'collectionItemCategories' because it has a DefiningQuery and no element exists in the element to support the current operation."
Have I missed something? Is this not the right way to do it? I try the same thing for removing and no luck there either.
I think I have managed to answer this one myself. After alot of digging around it turns out that the Entity Framework (as it comes in VS2008 SP1) doesn't actually support many to many relationships very well. The framework does create a list of objects from another object through the relationship which is very nice but when it comes to adding and removing the relationships this can't be done very easily. You need to write your own stored procedures to do this and then register them with Entity Framework using the Function Import route.
There is also a further problem with this route in that function imports that don't return anything such as adding a many to many relationship don't get added to the object context. So when your writing code you can't just use them as you would expect.
For now I'm going to simply stick to executing these procedures in the old fashioned way using executenonquery(). Apparently better support for this is supposed to arrive in VS2010.
If anyone feels I have got my facts wrong please feel free to put me right.
After you have created your Item object, you need to set the Item object to the Category object on the Item's Categories property. If you are adding a new Item object, do something like this:
Using (YourContext ctx = new YourContext())
{
//Create new Item object
Item oItem = new Item();
//Generate new Guid for Item object (sample)
oItem.ID = new Guid();
//Assign a new Title for Item object (sample)
oItem.Title = "Some Title";
//Get the CategoryID to apply to the new Item from a DropDownList
int categoryToAddId = Convert.ToInt32(ddlCategoriesRemaining.SelectedValue);
//Instantiate a Category object where Category equals categoryToAddId
var oCategory = db.CategorySet.First(x => x.ID == categoryToAddId);
//Set Item object's Categories property to the Category object
oItem.Categories = oCategory;
//Add new Item object to db context for saving
ctx.AddtoItemSet(oItem);
//Save to Database
ctx.SaveChanges();
}
Have you put foreign keys on both columns in your link table to the item and the category or defined the relationship as many to many in the Mapping Details?

Entity Framework: Why does the database get hit if the data is in the context?

Why would the database be hit to find a record that is already represented in the ObjectContext?
So here's what I thought would happen when you query:
SiteUser someUser = context.SiteUser.Where(role => role.UserID == 1).ToList()[0];
Junk example but the idea is that I want to get a user from the table with the id of 1. Now assume this is the first time through so what I would guess is that it has to create the SiteUser list on the context, query the database, and then fill it's list. Using profiler I see this:
SELECT
[Extent1].[UserID] AS [UserID],
[Extent1].[MainEmail] AS [MainEmail],
[Extent1].[Password] AS [Password],
[Extent1].[UserName] AS [UserName]
FROM [TIDBA].[TI_USER] AS [Extent1]
WHERE 1 = [Extent1].[UserID]
Beautiful. It did what I expect and in the SiteUser list (if I dig far enough using Watch) I can see that there is one item in the context SiteUser list and it happens to be the hydrated object that represents this data row.
Next I want to change something without saving:
someUser.UserName = "HIHIHI";
Now say for some reason I want grab it again Using the same context (This is a weird example but it's actually a test so I could prove this happening) :
someUser = context.SiteUser.Where(role => role.UserID == 1).ToList()[0];
What I think would happen is it would look at the SiteUser list on the context since that's what the generated property says. (If not null, return list) Then it would look to see if it's there and return it. No database hit. Guess what profiler says...
SELECT
[Extent1].[UserID] AS [UserID],
[Extent1].[MainEmail] AS [MainEmail],
[Extent1].[Password] AS [Password],
[Extent1].[UserName] AS [UserName]
FROM [TIDBA].[TI_USER] AS [Extent1]
WHERE 1 = [Extent1].[UserID]
Hrm. Ok so I start thinking that maybe it's a gut check to see if anything has changed on that data item and update the SiteUser object ONLY on values I haven't changed on the client. (Sort of like context.Refresh(RefreshMode.ClientWins, context.SiteUser) ) So I have it stopped at the :
someUser = context.SiteUser.Where(role => role.UserID == 1).ToList()[0];
Line and I change a value in the database (Password column) and let it hit the database. Nothing changed on the object.
Something doesn't seem right here. It hits the database to select the object I already have hydrated in the context yet it doesn't apply the change I manually made in the database. Why is it hitting the database at all then?
UPDATE
Thanks to some links below, I was able to dig in a bit and find this:
Merge Option
Looks like there is an enumeration that is set to tell how to deal with loads. Now after reading that I saw this for MergeOption.AppendOnly:
Objects that already exist in the
object context are not loaded from the
data source. This is the default
behavior for queries or when calling
the Load method on an
EntityCollection<(Of <(TEntity>)>).
This would suggest that if I have it in the context, there should be no hit to the database. However, this doesn't seem to be true. It would make sense if OverwriteChanges or PreserveChanges were the defaults, but they are not. This seems to be contradictory to what is supposed to happen. Only thing I can think of is that "loaded" just means there are no overwrites. However, it doesn't mean there are no queries to the database.
context.SiteUser is an property of type ObjectQuery. When you execute an ObjectQuery, it will always hit the backing store. That's what they do. If you don't want to execute a database query, then don't use an ObjectQuery.
It sounds like what you really want is a function which says, "If the entity is already materialized in the context, then just return it. If it isn't, then go grab it from the database." As it happens, ObjectContext includes such a function, called GetObjectByKey
GetObjectByKey tries to retrieve an
object that has the specified
EntityKey from the ObjectStateManager.
If the object is currently not loaded
into the object context, a query is
executed in an attempt to return the
object from the data source.
IMO, the reason that EF hits the database a second time is to make sure that there aren't any additional rows in the db that satisfy the query. It's possible that additional relevant rows have been inserted into the table since the first query was issued, and EF is seeing if any of those exist.
If I understand your question, this should answer it:
Actually, the way the entity framework
does this by default is to require
notifications of changes from the
entity objects to a framework class
called the state manager which then
keeps track of which properties have
been changed. The original values are
copied only on demand. When updates
happen, those original values are used
in talking to the server only if the
changed properties are marked as
“concurrency tokens”. That is, for
any concurrency token columns, when
the framework is creating an update
statement it will include a check to
verify that the row in the database
still has the original value, and if
not it will raise an exception to
notify the program that someone else
has changed the row in the database.
It’s also true that the entity
framework doesn’t absolutely require
notifications from the property
setters, you can also determine what’s
modified in the application code and
call an explicit method on the
framework to indicate which properties
are changed (but then the framework
will only have a record that the
property is modified, it won’t have an
original value).
Which comes from here. More can be read about it here, and here.
Edited to add:
It appears that with EF, there is an ObjectStateManager that tracks changes which never really allows for disconnected data. In order to have disconnected data, you'll have to call the ObjectContext.Detach method to disconnect your object. More can be found here and here.
What if you avoided the .ToList() and use .FirstOrDefault() ?