I want to store history in my table.
I have table Employee.
Employee
{
[Id],
[name],
[phone],
[isActive],
[createdDate],
[closedDate](default '23:59:59 9999-12-31'),
[DepartmentId] References Department(id)
}
When Employee is changed, I retrieve original values by Id and do isActive=False, closedDate=DateTime.Now and then I save modified value as new Employee with modified original values.
void UpdateEmployee(Employee employee)
{
ContextDB db=new ContextDB();
var employeeToUpdate=db.Employees.Find(it=>it.Id==employee.Id);
employeeToUpdate.isActive=false;
employeeToUpdate.closeDate=DateTime.Now;
var newEmployee=new Employee
{
Name=employee.Name,
Phone=employee.Phone,
....
}
db.Employees.AddObject(newEmployee);
// How I can do this with EF
db.Employees.Modify(employeeToUpdate);
db.SaveChanges();
}
How can I do this? And another question, what I need do if I have reference to another table Department and also want store history in this table. How should I do if changes Department in Employee object.
P.S. I use Self-Tracking Entities.
It should simply work without calling any Modify. You loaded entity from the database and you modified its fields while it is attached to the context so the context should know about changes and persist them to the database.
What I find totally bad about your architecture is that each change to your employee will result in active record with another Id. So if you are using and relation with employee table, foreign keys will not point to active record any more. If you want to do it this way you should not create a new record for active record but you should instead create a new record for deactivated record.
Related
Suppose a Company has Employees. Company 'Solutions' has Employee 'James'.
These entities are both saved in the DB, and their relationship is expressed through a foreign key.
At the application level, the Employee class has a Company object property, to define the relationship.
Suppose a new company 'Better Solutions' is created, which doesn't exist in the DB yet, and James now moves to this company.
How do I tell EF to handle this? Currently I:
Save the new company 'Better Solutions' (object created with a GUID ID) to the DB:
db.Companies.Add(newCompany);
Change the Company property on Jame's instance:
james.Company = newCompany;
Tell EF that a property on James's instance has changed and needs updating:
db.Employees.Attach(james);
db.Entry(james).State = System.Data.Entity.EntityState.Modified;
But when this happens, the newCompany object doesn't have its new database ID yet (even though it's been added to the database, the object still holds the GUID ID), so when saving EF tries to do this:
UPDATE [dbo].[Employee]
SET [CompanyID] = SomeGUID,
WHERE ([EmployeeID] = JamesID)
Which of course throws an exception because no CompanyID matches that GUID:
The UPDATE statement conflicted with the FOREIGN KEY constraint
In this scenario, do I need to first push the newCompany object to the DB, then retrieve it from the DB (to get the new ID), then set this retrieved object as James's Company property?
Or does EF have a cleaner way of taking care of all this?
try to do like below. Save company first then assign it to james that will update existing employee.
db.Companies.Add(newCompany);
db.SaveChanges();
james.Company = newCompany;
db.SaveChanges();
Let's say I have two tables: table Category and table Book
I would like to add a Category, then use its ID for inserting a book (which has a CategoryId field pointing to the table Category).
To get this info, I now commit my changes after inserting the category as it is not provided otherwise.
Is there a way to point to this category when inserting my book without commiting after inserting the category?
Thanks in advance
If the ID is generated by the database, then no, you can't get it until it is committed
It sounds like you have a FK relationship setup. If that's the case, if you associate the Category and Book entities together - EF should be create the necessary FK's.
For example:
var Category = new Category();
Book.Category = Category;
context.Books.Add(Book);
context.SaveChanges();
Would create a book, and a category and depending on how your mapping is setup the proper fields should be set. Can you post your model if this is not the case?
I'm having an issue inserting an instance of a subclass that inherits from a base class.
Consider the following code snippets from these POCOs:
public abstract class EntityBase<T>
{
private T _id;
[Key]
public T ID
{
// get and set details ommitted.
}
}
public abstract class PersonBase<T> : EntityBase<T>
{
// Details ommited.
}
public class Applicant : PersonBase<int>
{
// Details ommitted for brevity.
}
public class Employee : Applicant {}
Pretty standard inheritance right now. In our system, when an applicant finally becomes an employee, we collect extra data. If not hired, they remain an applicant with a limited set of information.
Now consider the fluent API that sets up the table-per-type inheritance model:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Set up table per type object mapping for the Visitor Hierarchy.
modelBuilder.Entity<Employee>().ToTable("Employees");
}
So far, so good...
If I look at the database this creates, I have a table named Applicants with an Id column of type int, auto-incrementing ID and I have an Employees table with an ID field as the primary key (non auto incrementing).
Basically, the ID field in the Employees table is a foreign key to the Applicants table.
This is what I want. I don't want a record into the Employees table corresponding to the Applicants table until they actually become an Employee.
The problem comes when I try to insert an Employee which comes down to this code:
public void PersistCreationOf(T entity)
{
DataContextFactory.GetDataContext().Set(typeof(T)).Add(entity);
}
The problem: It inserts a brand new applicant and Employee. I hooked it up to the Sql Profiler and looked at both insert queries that come down.
I want to just insert the Employee record with the ID it already has (the foreign key from the Visitors table).
I understand by default it needs to this: Obviously if you create a subclass and insert it, it needs to insert into both tables.
My question is is possible to tell the Framework - the base table already has information - just insert into the child table?
Thanks in advance!
Aside from sending raw SQL commands to insert the Employee minus Applicant properties fragment into the Employees table I believe it's impossible. You can either update or insert an entity. What you want is basically to update the base part of the Employee (or do nothing if nothing changed) and insert the derived part which is not possible.
Imagine what an ORM does: It maps key identities in the database to object identities in memory. Even in memory you couldn't achieve what you want: If you have an object in memory which is a Applicant, it is always an applicant. You cannot magically "upgrade" it to an Employee. You would have to create a new object of type Employee, copy the properties of the Applicant into the base properties of your new Employee and then delete the Applicant. The result is a new object with a new object identity.
I think you have to follow the same procedure in EF. Your Employee will be a new entity with new rows in both Applicant and Employee table and you need to delete the old Applicant. If you have autogenerated keys it will be a new identity with a new ID. (If you hadn't autogenerated keys you could supply the old ID again after deleting the old Applicant, thus "faking" an unchanged identity.) This will of course create big potential trouble if you have references to the old applicant with FK constraints.
Perhaps inheritance is not optimal for this scenario to "upgrade" an applicant into an employee. An optional navigation property (1-to-0...1 relationship) inside of the Applicant which refers to another entity containing the additional properties which make the applicant an employee would solve the problem. This navigation property could be set or not, letting you distinguish between an applicant and applicant which is also an employee. And you would not need to delete and change the ID of the applicant when you make it an employee.
(As said, "I believe". Maybe there is a hidden way, I didn't see.)
OK, I have 3 tables, call them:
Person
PersonID
Name
Store
StoreID
Name
PersonStore
PersonID
StoreID
Now, I have a form which allows you to add stores to a person. However, I am getting the store ID back from the form. I don't really want to do a query to get the store object from Entity Framework. I just want to add to the table using the StoreID and the Person object which I have.
By default in EF this join table won't appear as an entity instead you'll get a many to many relationship which will show up as two navigation properties
i.e.
Person.Stores
Store.People
If you want to build a many to many relationship without retrieving the entities then attaching stub entities is the best way.
var person = // you already have the person
var store = new Store{StoreID = 5} // you know the storeID
ctx.AttachTo("Stores", store);
ctx.AttachTo("People", person); // assuming the person isn't already attached
person.Stores.Add(store);
ctx.SaveChanges();
The only problem with this code is it will fail if the relationship already exists, so you need to be sure you are creating a new relationship
For more on using Stub entities like this check out my post.
Hope this helps.
Alex
Edit from OP:
Since I am using EF4, I used the following code to remove the string from the attach (thanks to tip 13 from the link).
var person = // you already have the person
var store = new Store{StoreID = 5} // you know the storeID
ctx.Stores.Attach(store);
person.Stores.Add(store);
ctx.SaveChanges();
Suppose I have
table Person
table Employee, which inherits Person.
I want to get a list of Person, regardless if this Person is Employee or not. How do you get entity framework to do that without joining the Employee table? C# is what I'm using. Thanks.
You need to make sure that you don't implicitly use any information from Employee.
If you do this:
var people = Context.People.ToList();
... Then me Entity Framework will initialize new instances of type Employee for those people who happen to be employees. This is because when you store an Employee in the database, you generally expect to get an Employee back when you select the same item.
Nor, for that matter, can you tell the Entity Framework to give you a Person when the stored value is an Employee. The Entity Framework will never give you back an incorrect entity type.
However, if you do just want to read the one table, there is a way to do that: Select the data from Person into a non-entity types, such as an anonymous type:
var people = Context.People.Select(p => new { Name = p.Name }).ToList();