UnionP
UnionP

Reputation: 1648

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

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.

Upvotes: 0

Views: 71

Answers (1)

Ward
Ward

Reputation: 17863

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.

Upvotes: 1

Related Questions