I have three tables in my database: An A table, a B table, and a many-to-many ABMapping table. For simplicity, A and B are keyed with identity columns; ABMapping has just two columns: AId and BId.
I built an Entity Framework 4 model from this, and it did correctly identify the N:M mapping between A and B. I then built a WCF Data Service based on this EF model.
I'm trying to consume this WCF Data Service. Unfortunately, I can't figure out how to get a mapping between As and Bs to map back to the database. I've tried something like this:
A a = new A();
B b = new B();
a.Bs.Add(b);
connection.SaveChanges();
But this doesn't seem to have worked. Any clues? What am I missing?
You need to do the following:
A a = new A();
B b = new B();
connection.AddObject("ASet", a);
// if you have the generated code, you can use the helper method generated
// on the context - something like connection.AddToASet(a);
connection.AddRelatedObject(a, "Bs", b);
connection.SaveChanges();
Related
I need to know information about entities, tables, mappings, keys etc for the given instance of DbContext. In Entity Framework 6 I was writing edmx like this:
System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(dbContext, xmlWriter);
which I then used to build my own data model (this is needed for a tool which supports loading data from different sources). How do I get such information for the new EF Core (previous EF 7)? I could use Reflection, but this will give me only the conceptual schema, while I also need mappings and storage schema. I've been looking through the EF source code for a while now, but don't seem to find any object, that stores all the required data.
This should get you started
using (var ctx = new TestContext())
{
var entityType = ctx.Model.FindEntityType(typeof (Entity_Basic));
var tableName = entityType.SqlServer().TableName;
var columnName = entityType.GetProperties().ToList()[0].SqlServer().ColumnName;
}
I have an ERD with a main table (A) which has one attribute(String) that is a FK to another table (B).
The issue that I have is that in B the only attribute is the PK; I just want to ensure that the user inputs only one of the allowed values in the main table attribute. I do not even want to update the B table from the application, as it will be a task so unusual that I'll do it directly in the DB.
I could treat B just as another Entity and deal with them with "regular" JPA, but I am a little troubled that maybe there are more efficient ways to do it*. All I want from B table is to get the full list of values and to ensure that the attribute value is correct.
So the question is: there is a specific pattern in JPA to deal with those master tables?
Thanks In advance.
*: My concern is creating / retrieving Entity B objects when all that it is needed is an string, every time an Entity A object is created retrieved.
I would simply use a native query to get all the strings from the B table, or map B as an entity to retrieve all the B Strings using a JPQL query, but not have any association from A to B.
The B string would be stored as basic String column in entity A. And if you try creating or updating an A instance with a string that is not in the B table, then you'll get an exception at flush or commit time because the foreign key constraint is broken.
I tried searching the SO, but all results I've found seem to deal with updating PK of entities that have already been persisted to the DB. My case is different.
I have 3 tables in a database with 1-0..1 relationships. The relationships look like this:
A <- B <- C
where '<-' represents a relationship and points to the principal end. I.e. each B always has a related A, but an A can have no B. In other words, A's cardinality is 1 and B's is 0..1.
Each relationship is represented by a FK that goes from the child entity's PK to the parent entity's PK. Each PK is a uniqueidentifier Id column with client-generated value. I've generated an EF 4 model from the database which has the same relationships with same cardinality.
I'm trying to add child entites B and C to an existing A entity. For design reasons the couple of new instances is created in one peace of code, and the A entity is linked to the B entity in another one. Furthermore, I don't want the latter one to know that C exists.
Here's how the B and C creation code looks like:
public B CreateB()
{
return new B
{
Id = Guid.NewGuid(),
C = new C(),
};
}
And now the link and save code:
// a is an instance of A that has been loaded from DB
// and hence has a persistent Id value.
// b is a just-created instance of B
// that has a non-persistent Id value and null reference to A.
void SaveBlahBlahBlah(A a, B b)
{
// At this point b and c have the same Id value.
// It differs from a's Id, but that's expected, they haven't been linked yet.
b.A = a;
// At this point b receives a's Id value, but c keeps the original one,
// therefore the existing b-c link gets broken!
using(var ctx = new MyContext())
{
ctx.As.Attach(a); // This throws exception saying
// I've violated referential integrity.
// It doesn't say which relationship is broken,
// but I guess it's the B-C one since
// the debugger shows them to have different values if PKs
ctx.Bs.AddObject(b);
ctx.SaveChanges();
}
}
I've tried this both with the default EF's code generator (the one that uses EF's Entity class as base class for generated entities) and with the Self-Tracking Entities code generator. The result is the same.
So, the code crashes. The reason is likely to be that after A and B have been linked, B and C get different PK values which is illegal for entities with 1-1 relationship.
What I expected was C to automatically get it's PK synchronized to the value B got from A instance. That seems reasonable because I work with an object graph, I have an existing B-C relation which is OK and I expect it to remain OK after linking B with A. Why would it break? I would understand it if either B or C existed in DB and I wasn't able to change their PKs. But it's not the case, both entites have been just created.
I cannot break the chain of keys by using separate from PKs columns for FKs because EF requires both sides of a 1-1 relationship to be the PKs.
I don't want to sync keys manually because in fact there are more 1-1 related tables and that would require the sync code to appear in many places.
I believe I will be able to update the T4 template of the STE generator to cascade PK updates down 1-1 relationships. But I'm not too familiar with T4 and not too happy to do that.
I have 2 questions:
Is my expectation of cascaded PK updates in my case wrong for some reasons? (Seems bizarre though) I.e., is it a bug or a feature?
Are there any other and preferably simpler ways to fix the issue than modifying the STE template? Maybe some magic options in EF mappings or context?
Thanks in advance.
The problem is that the service which handles the assignment of IDs from one referenced object to another is the context. But at the time when you actually make the association, neither object is in the context. That wouldn't normally be a problem because the relationship will be fixed up when you add B to the context.
Unfortunately, you don't do this. Instead, you create an additional relationship with A, but then lie to the context and claim that everything is already fixed up. More precisely, you call EntitySet.Attach, which is really only intended for already fixed-up objects.
On the other hand, code like this should work just fine:
public B CreateB()
{
return new B
{
Id = Guid.NewGuid(),
C = new C(),
};
}
void SaveBlahBlahBlah(A a, B b)
{
using(var ctx = new MyContext())
{
ctx.Bs.AddObject(b);
ctx.SaveChanges();
}
}
Note that all I've done here is delete the problematic code, which has nothing to do with the relationship between B and C.
In short, beware of Attach. You need to know what you're doing when you call it.
UPDATE
A version that handles existing instances of A:
void SaveBlahBlahBlah(A a, B b)
{
Debug.Assert(a.B != b);
using(var ctx = new MyContext())
{
ctx.As.Attach(a);
a.B = b; // it's crucial that this link is set after attaching a to context!
ctx.Bs.AddObject(b);
ctx.SaveChanges();
}
}
I have table name Transaction in the DB. I want to have 2 subclasses TransactionA and TransactionB. I've made it as described here: http://www.robbagby.com/entity-framework/entity-framework-modeling-table-per-hierarchy-inheritance/comment-page-1/#comment-607
As I use T4 templates I've generated self-tracking entities.
Everything is okay but one thing. I can see generated entities TransactionA and TransactionB but I cannot see them in the context object (ObjectContext). Is it normal? If so, how could I get TransactionB from the table using context if only Transaction class is accessible?
Thanks
This is as expected. Transaction A en B derive from the baseclass Transaction. In your entity model you can access them through the collection of Transactions like this:
Context context = new Context();
List<TransactionB> list = context.Transactions.OfType<TransactionB>().ToList();
I want to know if there is way to create a database out of existing classes with the ado.net entity framework or to map existing classes to a database.
I looked for tutorials and only found ways to create the classes with the entity model designer.
As an example I have the class Bird with Properties Length and Age
On the database I have a table named Bird with columns Length and Age
Now I don't want the designer to create new classes out of the database. Instead I want to map the Class Bird directly to the table Bird. With Linq2Sql this was possible by creating the mapping manually. Is there a possibility in the ado.net entity framework?
With kind regards
Sebastian
What's the difference between mapping a class C onto a table T or mapping T onto a class C ?
O/R mapping isn't about mapping classes to tables, it's about defining an entity model and projecting it to tables AND classes simultaneously. After all, your classes and tables don't fall out of the sky: they're based on definitions you have, e.g. there has to be an entity customer, with fields A, B and C, and THEN you're defining the entity Customer with fields A, B and C which leads to a table Customer with fields A, B and C and a class Customer with fields / properties A, B and C and the mapping between them, because they represent the same entity