breezeManager.createEntity() fails to populate foreign key property for a specific value - entity-framework

I have two relevant tables here:
public partial class List
{...
public int RegionId { get; set; }
[ForeignKey("RegionId")]
public virtual Region Region { get; set; }
...}
public partial class Region
{
public Region()
{
Lists = new HashSet<List>();
}
public int RegionId { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
public DateTime Added { get; set; }
public virtual ICollection<List> Lists { get; set; }
}
Here's the contents of the Regions table:
RegionId Name
1 Global
2 China
3 USA
4 UK
8 Canada
9 Spain
10 France
On the breeze side of things, I pull down the Regions:
var query = new breeze.EntityQuery().from("Regions").select("RegionId,Name").orderBy("RegionId");
return $rootScope.breezeManager.executeQuery(query).then(function (data) {
service.regions = data.results;
It seems to work:
service.regions[2]; // Name: "USA", RegionId: 3
However, when I try to create a new entity:
var newList = $rootScope.breezeManager.createEntity('List', listValues);
And in listValues, I specify { RegionId: 3, ...}:
newList.RegionId // 3
newList.Region // null
That would be strange already perhaps, but the really frustrating thing is, if I specify another value, like 1, it works. Same for 2, and 4:
newList.RegionId // 1
newList.Region.Name // "Global"
I've been poring through the code (and the internet) for hours trying to figure this out, but it's eluded me, and thus qualifies for my first ever SO question!
Update
I'm now even more confused. I planned to workaround this by manually setting the Region after the createEntity call, so I added this line of code right above createEntity:
var region = Enumerable.From(service.regions).Single("$.RegionId == " + listValues.RegionId);
However, after doing so, and with no other changes, newList now correctly gets a populated Region, even for 3 (USA)! I then commented out that line and tried again, and it still worked. Tried a few other times, various combinations of things, and now it's not working again, even with that line. Not sure if that helps. I'll keep experimenting.

I don't know what you're trying to do exactly but I do see that you have a fundamental misunderstanding.
I believe you are expecting your first query to return Region entities and you think that service.regions is populated with Region entities in the success callback.
Neither is true. Your query contains a select() clause which makes it what we call a projection. A projection returns data objects, not entities. There are no Region entities in cache either.
You may have seen elsewhere - perhaps a Pluralsight video - where a projection query did return entities. That happens when the query includes a toType clause which actually casts the projected data into instances of the targeted type. That's a trick you should only perform with great care, knowing what you are doing, why, and the limitations. But you're not casting in this query so this digression is besides the point.
It follows that the service.regions array holds some data objects that contain Region data but it does not hold Region entities.
This also explains why, when you created a new List entity with RegionId:3, the new entity's Region property returned null. Of course it is null. Based only on what you've told us, there are no Region entities in cache at all, let alone a Region with id=3.
I can't explain how you're able to get a Region with id=1 or id=2. I'm guessing there is something you haven't told us ... like you acquired these regions by way of some other query.
I don't understand why you're using a projection query in the first place. Why not just query for all regions and be done with it?
breeze.EntityQuery.from("Regions").orderBy("RegionId")
.using(manager).execute(function(data) {
service.regions = data.results;
});
I don't understand your update at all; that doesn't look like a valid EF query to me.
Tangential issues
First, why are you using a HashSet<List> to initialize the Lists property in your server-side Region model class? That's a specialized collection type that only confuses matters here. It doesn't do what the casual reader might think it does. While it prevents someone from adding the same object reference twice, it doesn't do the more important job of preventing someone from adding two different List objects with the same RegionId. The simple, obvious, and correct thing to do is ...
Lists = new System.Collections.Generic.List<List>();
// the full type name is only necessary because you burned the name "List"
// when defining your model class.
Second, on the client-side, please don't extend the Angular $rootScope with anything. That kind of global variable "pollution" is widely regarded as "bad practice". Keep your Breeze stuff inside a proper Angular service and inject that service when you need something.

Related

Do I need a foreign key in the EF core code first?

I'm new at code first in entity framework and reading up on relationships, I see everyone does it differently. It might be because of earlier versions, might be the same or might be because of performance.
Let's say I have two tables Company and User.
I would set the company-to-user relationship like this:
public List<User> Users { get; set; } = new List<User>();
Then if I from the user-to-company perspective needed to find the company, I would have this in the User:
public Company Company { get; set; }
And do this query:
return await _clientContext.Users.Where(x => x.Company.Id == companyId).ToListAsync();
Or I could have this:
public int CompanyId { get; set; }
[ForeignKey("CompanyId")]
public Company Company { get; set; }
And have this query:
return await _clientContext.Users.Where(x => x.CompanyId == companyId).ToListAsync();
Also some define Company with the keyword virtual like this:
public virtual Company Company { get; set; }
I'm not sure if every scenario is the same and doing x.CompanyId instead of x.Company.Id would actually be the same. What is used normally?
I generally recommend the first option using Shadow Properties for FKs over the second when using navigation properties. The main reason is that with the second approach there are two sources of truth. For instance with a Team referencing a Coach, some code may use team.CoachId while other code uses team.Coach.CoachId. These two values are not guaranteed to always be in sync. (depending on when you happen to check them when one or the other is updated.)
Updating references between entities via a FK property can have varied behaviour depending on whether the referenced entity is loaded or not.
What is the expected difference between if want to update a team's coach:
var teamA = context.Teams.Single(x => x.TeamId == teamId);
If Team has a Coach navigation property and a CoachId FK reference I could do...
teamA.CoachId = newCoachId;
If TeamA's old coach ID was 1, and the newCoachId = 2, what do you think happens if I have code that lazy loads the coach before SaveChanges?
var coachName = teamA.Coach.Name;
You might expect that since the Coach hadn't been loaded yet it would load in Coach #2's name, but it loads Coach #1 because the change hasn't been committed even though teamA.CoachId == 2. If you check the Coach reference after SaveChanges you get Coach #2.
Depending on whether lazy loading is enabled or not you can get a bit strange behaviour by setting a FK property where navigation properties are nulled. Even when eager loading, changing a FK property will potentially trigger a new lazy load if that new entity isn't already tracked:
var teamA = context.Teams.Include(x => x.Coach).Single(x => x.TeamId == teamId);
teamA.CoachId == newCoachId;
var coachName = teamA.Coach.Name; // Still points to Coach #1's name as expected.
context.SaveChanges();
coachName = teamA.Coach.Name; // Triggers lazy load and return new coach's name.
Saving a FK against an entity that has eager loaded the reference does not automatically re-populate referenced entities. So for instance if you have lazy loading disabled, the same above code:
context.SaveChanges();
coachName = teamA.Coach.Name; // Potential NullReferenceException on teamA.Coach.
This will potentially trigger a null reference exception unless the new coach happens to be tracked by the DbContext prior to SaveChanges being called. If the DbContext is tracking the entity, the new reference will be swapped in on SaveChanges, otherwise it is nulled. (With lazy loading this is covered by the new lazy load call after it was nulled)
When working with navigation properties my default recommendation is to hide FK properties as Shadow Properties. (For EF6 this means using .Map(x => x.MapKey()). For relationships where I only care about the ID, I will expose the FK with no navigation property. So, one or the other. (Such as lookups or bounded contexts where I want raw speed.)
I will deviate sparingly from this for exposing FKs for relationships I may inspect by ID frequently, and treat it as read-only, but still have infrequent need of the navigation property. An example of this would be CreatedBy / CreatedByUserId. Many queries may inspect the CreatedByUserId for data filtering, while some projections may want the CreatedBy.Name etc. A record's CreatedBy doesn't change so I avoid potential pitfalls of the data getting out of sync.
Your second scenario is used normally.
i.e.
public int CompanyId { get; set; }
[ForeignKey("CompanyId")]
public Company Company { get; set; }
And have this query:
return await _clientContext.Users.Where(x => x.CompanyId == companyId).ToListAsync();

How to explicitly set the ID property on an autoincrementing table in EFCore

I have a model which has an auto-incrementing ID field by default as is normal. However, I wish to seed the database with initial data and because there are foreign keys I wish to explicitly set the IDs of the seeded data.
My model
public class EntAttribute
{
public int ID { get; set; }
public string Title { get; set; }
}
My seeding code:
public class Seeder
{
private class AllAttributes
{
public List<EntAttribute> Attributes { get; set; }
}
public bool SeedData()
{
AllAttributes seedAttributes;
string strSource;
JsonSerializer JsonSer = new JsonSerializer();
strSource = System.IO.File.ReadAllText(#"Data/SeedData/Attributes.json");
seedAttributes = JsonConvert.DeserializeObject<AllAttributes>(strSource);
_context.AddRange(seedAttributes.Attributes);
_context.SaveChanges();
return true;
}
}
Please note, I'm very new to both EFCore and C#. The above is what I've managed to cobble together and it seems to work right up until I save the changes. At this point I get:
SqlException: Cannot insert explicit value for identity column in table 'Attribute' when IDENTITY_INSERT is set to OFF.
Now I'm smart enough to know that this is because I can't explicitly set the ID field in the EntAttribute table because it wants to assign its own via auto-increment. But I'm not smart enough to know what to do about it.
Any help appreciated.
EDIT: Adding the solution based on the accepted answer below because the actual code might help others...
So I added to my Context class the following:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasSequence<int>("EntAttributeNumbering")
.StartsAt(10);
modelBuilder.Entity<EntAttribute>()
.Property(i => i.ID)
.HasDefaultValueSql("NEXT VALUE FOR EntAttributeNumbering");
}
This first ensures the a sequence is created (the name is arbitrary) and then secondly, sets it to be used for the relevant table instead of auto-increment. Once this was done I was able to my seed data. There are fewer than 10 records so I only needed to set the start value for the sequence to 10. More would normally make sense but I know there will never be more.
I also had to blitz my migrations because they'd somehow got in a mess but that's probably unrelated.
With EF Core you can create and use a Sequence object to assign the IDs, and you can reserve a range of IDs for manual assignment by picking where the sequence starts. With a Sequence you can assign the IDs yourself, or let the database do it for you.
FYI for people using EF Core 3, if using int for your key you can set the start sequence value incase you have seeded data. I found this a much cleaner to solve this problem in my use case which just had a single seeded record.
e.g
modelBuilder.Entity<TableA>()
.Property(p => p.TableAId)
.HasIdentityOptions(startValue: 2);
modelBuilder.Entity<TableA>()
.HasData(
new TableA
{
TableAId = 1,
Data = "something"
});
https://github.com/npgsql/efcore.pg/issues/367#issuecomment-602111259

Entity Framework 5 table-per-type update, change sub type but keep same base type

I have a simple hierarchy
public abstract class CommunicationSupport
{
public SupportTypeEnum Type { get; set; }
public Country Origin { get; set; } // National or Foreign support
}
public class TelecomSupport : CommunicationSupport
{
public string Number { get; set; }
}
public class PostalSupport : CommunicationSupport
{
public Address Address { get; set; }
}
I plan to use the Table-per-type hierarchy for my DB. So 3 tables will be created, one base and two child using the same PK as the base.
My problem is that I want to be able to update a CommunicationSupport by changing it's type.
Let's say that I create a TelecomSupport, save it and then change it's type to a PostalSupport and save it again (update). The result I expect is for EF to keep the same base record (CommunicationSupport Id) but delete the record in the TelecomSupport table and create a new one in the PostalSupport.
So TelecomSupport and PostalSupport are exclusive and cannot share the same base CommunicationSupport.
How can I do that using EntityFramework 5?
Thanks for your help!
I don't have a good answer, but I can think of four "solutions" that are really workarounds:
Don't use DBMS-computed values for your primary keys (if you already use natural keys, it's fine).
Use DBMS-computed surrogate keys.
Follow something like the state pattern.
Do some evil voodoo with the object state manager.
Update: There seems to be a popular consensus that trying isn't even worth it; most people thus simply use stored procedures instead to work around the problem.
Changing Inherited Types in Entity Framework
Entity Framework: Inheritance, change object type
Changing the type of an (Entity Framework) entity that is part of an inheritance hierarchy
Changing the type of an entity that is part of an inheritance hierarchy
Using natural keys
First, remember that the objects tracked by the EF are part of your DAL, not your domain model (regardless of whether you use POCOs or not). Some people don't need a domain model, but keep it in mind, as we can now think of these objects as representations of table records we manipulate in ways we wouldn't with domain objects.
Here, we use IDbSet.Remove to delete the records of the entity, then add new ones with the same primary key using IDbSet.Add, all in a single transaction. See the ChangeType method in the sample code below.
In theory, integrity is OK, and in theory, EF could detect what you're trying to do and optimize things. In practice, it currently doesn't (I profiled the SQL interface to verify this). The result is that it looks ugly (DELETE+INSERT instead of UPDATE), so if system beauty and performance are issues, it's probably a no-go. If you can take it, it's relatively straightforward.
Here is some sample code I used to test this (if you want to experiment, simply create a new console application, add a reference to the EntityFramework assembly, and paste the code).
A is the base class, X and Y are subclasses. We consider Id to be a natural key, so we can copy it in the subclasses copy constructors (here only implemented for Y). The code creates a database and seeds it with a record of type X. Then, it runs and changes its type to Y, obviously losing X-specific data in the process. The copy constructor is where you would transform data, or archive it if data loss is not part of the business process. The only piece of "interesting" code is the ChangeType method, the rest is boilerplate.
using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
namespace EntitySubTypeChange {
abstract class A {
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public string Foo { get; set; }
public override string ToString() {
return string.Format("Type:\t{0}{3}Id:\t{1}{3}Foo:\t{2}{3}",
this.GetType(), Id, Foo, Environment.NewLine);
}
}
[Table("X")]
class X : A {
public string Bar { get; set; }
public override string ToString() {
return string.Format("{0}Bar:\t{1}{2}", base.ToString(), Bar, Environment.NewLine);
}
}
[Table("Y")]
class Y : A {
public Y() {}
public Y(A a) {
this.Id = a.Id;
this.Foo = a.Foo;
}
public string Baz { get; set; }
public override string ToString() {
return string.Format("{0}Baz:\t{1}{2}", base.ToString(), Baz, Environment.NewLine);
}
}
class Program {
static void Main(string[] args) {
Display();
ChangeType();
Display();
}
static void Display() {
using (var context = new Container())
Console.WriteLine(context.A.First());
Console.ReadKey();
}
static void ChangeType()
{
using (var context = new Container()) {
context.A.Add(new Y(context.A.Remove(context.X.First())));
context.SaveChanges();
}
}
class Container : DbContext {
public IDbSet<A> A { get; set; }
public IDbSet<X> X { get; set; }
public IDbSet<Y> Y { get; set; }
}
static Program() {
Database.SetInitializer<Container>(new ContainerInitializer());
}
class ContainerInitializer : DropCreateDatabaseAlways<Container> {
protected override void Seed(Container context) {
context.A.Add(new X { Foo = "Base Value", Bar = "SubType X Value" });
context.SaveChanges();
}
}
}
}
Output:
Type: EntitySubTypeChange.X
Id: 0
Foo: Base Value
Bar: SubType X Value
Type: EntitySubTypeChange.Y
Id: 0
Foo: Base Value
Baz:
Note: If you want an auto-generated natural key, you can't let EF ask the DBMS to compute it, or EF will prevent you from manipulating it the way you want (see below). In effect, EF treats all keys with computed values as surrogate keys, even though it still happily leaks them (the bad of both worlds).
Note: I annotate the subclasses with Table because you mentioned a TPT setup, but the problem is not actually related to TPT.
Using surrogate keys
If you consider a surrogate key to be truly internal, then it doesn't matter if it changes under your nose as long as you can still access your data the same way (using a secondary index for example).
Note: In practice, many people leak surrogate keys all around (domain model, service interface, ...). Don't do it.
If you take the previous sample, simply remove the DatabaseGenerated attribute and the assignment of the Id in the copy constructor of the subtypes.
Note: With its value generated by the DBMS, the Id property is completely ignored by EF and doesn't serve any real purpose other than being analyzed by the model builder to generate the Id column in the SQL schema. That and being leaked by bad programmers.
Output:
Type: EntitySubTypeChange.X
Id: 1
Foo: Base Value
Bar: SubType X Value
Type: EntitySubTypeChange.Y
Id: 2
Foo: Base Value
Baz:
Using the state pattern (or similar)
This solution is probably what most people would consider the "proper solution", since you can't change the intrinsic type of an object in most object-oriented languages. This is the case for CTS-compliant languages, which includes C#.
The problem is that this pattern is properly used in a domain model, not in a DAL like one implemented with EF. I'm not saying it's impossible, you may be able to hack things up with complex types or TPH constructs to avoid the creation of an intermediary table, but most likely you'll be swimming up the river until you give up. Hopefully someone can prove me wrong though.
Note: You can decide that you want your relational model to look different, in which case you may bypass this problem altogether. It wouldn't be an answer to your question though.
Using internal EF voodoo
I've rather quickly looked around the reference documentation for DbContext, ObjectContext and ObjectStateManager, and I can't immediately find any way to change the type of an entity. If you have better luck than me, you may be able to use DTOs and DbPropertyValues to do your conversion.
Important note
With the first two workarounds, you'll likely hit a bunch of problems with navigational properties and foreign keys (because of the DELETE+INSERT operation). This would be a separate question.
Conclusion
EF is not that flexible when you do anything non-trivial, but it keeps improving. Hopefully this answer won't be relevant in the future. It's also possible that I'm not aware of an existing killer-feature that would make what you want possible, so don't make any decisions based on this answer.

Modeling Question for RavenDB (Or other doc oriented databases)

Wondering how some of the more experienced (or anyone with a better idea than I have) would tackle my particular modeling scenario...
I have a typical "Category -> SubCategory ->TertiarySubCategory" scenario and I'm not sure if I'm mapping it out correctly. I am mapping this directly to an MVC route since raven seems to lend itself well with this. Under the final category (which can be at the first, 2nd or 3rd levels there will be a list of items associated with only that level of a category. So, we might have something like:
Single level category: '/Politics/'
Second level category: 'Politics/People' or 'Politics/Websites'
Tri-Level Category: 'Sports/Pro/Volleyball' or 'Sports/College/Football'
In a traditional RDBMS this is easy through primary/foreign keys + a few joins... so, wondering how I would handle with Raven?
From what I have read should I store the entire 'sports/pro/volleyball' URI or Key in a list of items that fall under it?
i.e. -
public class CategoryItem
{
public string FriendlyName {get;set;} // Volleyball or Pro Volleyball
public string CategoryURI {get;set;} // i.e. - "/sports/pro/volleyball/"
public string content {get;set;} // i.e. - "Who is the best Pro Volleyball Athlete?"
public List<string> Comments {get;set;}
}
// then we could store something like this:
var survey1 = new CategoryItem();
survey1.CategoryURI = "/sports/pro/volleyball/"
survey1.Content = "Who is the best female pro volleyball player?";
survey1.Comments.Add(new Comment("Misty May"));
var survey2 = new CategoryItem();
survey2.CategoryURI = "/sports/pro/volleyball/";
survey2.Content = "Who is the best male pro volleyball player?";
survey2.Comments.Add(new Comment("Some guy I don't kow");
// asuumes ravenSession was alreadyopened...
ravenSession.Store(survey1);
ravenSession.Store(survey2);
ravenSessoin.SaveChanges();
//{ ...... etc ..... }
//Then I can query by CategoryURI without needing joins (denormalization).... i.e. -
var items = session.Query<CategoryItem>()
.Where(x => x.CategoryURI == "/sports/pro/volleyball/");
Or should I create a List items member of the actual category class? Each item would have a list of it's own comments... meaning everything's stored in a single document within Raven - i.e. -
public class Category
{
public string FriendlyName {get;set;} // i.e. - "Volleyball" or "Pro Volleyball"
public string URI {get;set;} // i.e. - "/sports/pro/volleyball" which is the MVC path
public List<CategoryItem> Items {get;set;}
}
public class CategoryItem
{
public string Content {get;set;}
public List<string> Comments {get;set;}
}
var vballCat = new Category();
vballCat.FriendlyName = "Pro Volleyball";
vballCat.URI = "/sports/pro/volleyball/"; // equivalent to the MVC route
var catItem = new CategoryItem().
catItem.Content = "Who is the best male pro volleyball player?";
catItem.Comments.Add("Misty May");
catItem.Comments.Add("Some Guy 1");
vballCat.Items.Add(catItem);
ravenSession.Store(vballCat);
ravenSession.SaveChanges();
..... now once I pull the primary cat i.e. - "/sports/pro/volleyball/" I have everything I need already under it
var items = session.Query<Category>()
.Where(x => x.URI == "/sports/pro/volleyball/");
{ ............. etc ............... }
Now here I can just iterate through the Items collection and it's collection of comments.... does this use eager loading? What if I had a million comments under one category item? When I load the main category would it load all one million comments too!?!?
I would appreciate any help you can provide. Sorry if this example/question is unclear... I'll try to clarify anything if you guys need it. Thanks again!
The answer is that it depends on the size of your data and your usage scenario.
The first example is useful if you have large number of items and want to access categories without its items.
The second example is useful if you usually access category with its items, and the size of items is limited (note that limited is still high, several thousands wouldn't cause me to blink).
Note that there is no such thing as eager / lazy loading in RavenDB, you are talking about a single document vs. multiple documents, not about relations between documents. The entire document is loaded when you need it.
Another thing to remember is that it is usually faster to query by id than querying. That means that if you have ids that already looks very much like Document Ids, you might as well MAKE them the document ids.

EF4 POCO one to many Navigation property is null

I'm using VS2010, EF4 feature CTP (latest release), and POCO objects, such as the example below:
class Person
{
public int ID { get; set; }
public string Name { get; set; }
public virtual IList<Account> Accounts { get; set; }
...
}
class Account
{
public string Number { get; set; }
public int ID { get; set; }
...
}
For the sake of brevity, assume context below is the context object for EF4. I have a dbml mapping between entity types and the database, and I use it like this with no problem:
Person doug = context.Persons.CreateObject();
doug.Name = "Doug";
context.Add(doug);
context.Save();
doug.Accounts.Add(new Account() { Name = "foo" });
context.Save(); // two calls needed, yuck
At this point, the database has a Person record with the name "Doug", and an account record "foo". I can query and get those record back just fine. But if I instead try to add the account before I save the Person, the Accounts list is null (the proxy hasn't created an instance on that property yet). See the next example:
Person doug = context.Persons.CreateObject();
doug.Name = "Doug";
doug.Accounts.Add(new Account() { Name = "foo" }); // throws null reference exception
context.Add(doug);
context.Save();
Has anybody else encountered this? Even better, has anyone found a good solution?
Person doug = context.Persons.CreateObject();
doug.Name = "Doug";
context.Add(doug);
doug.Accounts.Add(new Account() { Name = "foo" });
context.Save();
This will work
Yes and yes!
When you new the POCO up (as opposed to CreateObject from the Context), no proxies are provided for you. This may seem obvious, but I had to explicitly remind myself of this behavior when chasing a similar issue down. (I know this isn't the situation you described in the question, but the overall issue should be acknowledged).
Initializing collections in the constructor of the POCO does not interfere with proper EF4 proxy lazy-loading behavior, from what I've observed in my own testing.
OK, all this being said, I now see your comment to the previous answer -- why don't I have a proxied Addresses collection when I request a new Person from my context? Do you have lazy loading enabled on the context? Seeing how we're dealing with navigation properties, I could see where having lazy loading turned off may make a difference in this situation.
ISTM that if you expect the framework to do all this for you then you wouldn't really have a "POCO", would you? Take your Person class, with the code above. What would you expect the state of the Accounts property to be after construction, with no constructor, if the EF weren't involved? Seems to me that the CLR will guarantee them to be null.
Yes, proxies can initialize this when necessary for materialization of DB values, but in the EF, "POCO" actually means "Plain". Not "something packed with runtime-generated code which we pretend is 'Plain'".