Aggregate root updated when child modified - entity-framework-4.1

I'm using EF 4.2 where the relevant bits look like:
public class MyDbContext : DbContext
{
public IDbSet<User> Users { get; set; }
public IDbSet<Membership> Memberships { get; set; }
}
public User()
{
public int Id { get; set; }
public string Email { get; set; }
public virtual Membership Membership { get; set; }
}
If I pull back a particular User and then update the associated Membership object (to say update the failed password count) the Membership object gets updated, but so does the User despite the fact that none of the User properties have been updated. Is this because the Membership object has fired some sort of changed event and it's bubbled up to the parent User?
This occurs even if I load the User and then get the Membership using _context.Memberships.Find(userId) rather than just using the user.Membership navigation property. I'm guessing in the context graph these two are equivalent?
Is there any way to stop the User object being updated as I use a calculated value column of date modified and I would prefer this were not updated when the child entity is altered. Ideally I want to pull back the User object rather than just querying the Membership DbSet as I want to read some of the User properties too.
The SQL which is fired on the parent Users table is:
update [dbo].[Users]
set #p = 0
where (([Id] = #0) and ([Version] = #1))

Related

Anonymous object blob in database not serializing as JSON when queried

I have a need to store an unknown data structure in a SQL Server database table field via ORMLite. This is to support a timeline feature on a website where each step on the timeline contains different information, and I want to store them as generic "Steps", with the variable data in a "StepData" property. I have the POCO set up like this:
public class ItemStep
{
public ItemStep()
{
this.Complete = false;
}
[Alias("ItemStepId")]
public Guid Id { get; set; }
[References(typeof(Item))]
public Guid ItemId { get; set; }
[References(typeof(Step))]
public int StepId { get; set; }
public object StepData { get; set; }
[Reference]
public Step Step { get; set; }
public bool Complete { get; set; }
public DateTime? CompletedOn { get; set; }
}
My front-end send a JSON object for StepData, and it's saved to the database appropriately.
{itemAmount:1000,isRed:False,isBlue:True,conversion:True}
Now, when I go to retrieve that data using...
List<ItemStep> itemSteps = Db.Select<ItemStep>(q => q.ItemId == request.ItemId).OrderByDescending(q => q.StepId).ToList<ItemStep>();
...the "StepData" node of the JSON response on the client is not a Javascript Array object as I'm expecting. So, on the client (AngularJS app using Coffeescript),
ItemStep.getItemSteps(ItemId).then((response) ->
$scope.StepData = response.data.itemSteps[0].stepData
is a double-quoted string of the JSON array.
"{itemAmount:1000,isRed:False,isBlue:True,conversion:True}"
Can anybody help me with this? I've tried parsing that string as JSON and I can't seem to get it to work:
JSON.parse($scope.StepData)
I'm using the exact same methodology in other areas of the app to store and retrieve things like addresses, with the only difference I can see being that there is a specified Address class.
Thanks!
Found this link that solved my problem: https://github.com/ServiceStackV3/mythz_blog/blob/master/pages/314.md
Essentially I added a "Type" field to the ItemStep class, and set that when I create a new row (create the next step in the timeline). Then, when I retrieve that record, I call a method like "GetBody" in the referenced link (GetStepData for me), that deserializes the object using the stored Type. I then stuff that back into a generic "object" type in the return POCO so that I can include many steps of varying types in the same call. Works great!
Thanks Mythz for the blog post!

Save DropDownListFor multiple selected values

How can I save data for a multiple DropDownListFor? I have this code but the selected items aren't reaching the controller.
My code view:
#Html.DropDownListFor(model => model.Ingredients, new SelectList(Model.ListIngredients, "Id", "Description"), "Select the ingredients", new { multiple = "multiple", })
My model:
public ICollection<Ingredient> Ingredients { get; set; }
public ICollection<Ingredient> ListIngredients{ get; set; }
Ingredient.cs:
public string Description { get; set; }
public int Id { get; set; }
I have to change the name and id of my helper for data to be saved?
You are trying to bind the selected values into a collection of Ingredients.
However if you take a look at the posted values, they will look something like this:
...Ingredients=1&Ingredients=2...
That means the model binder will not know how to convert values like 1,2 (which are the ingredient Ids) into instances of the ingredient class.
You need to change the property of your view model where you will get the ingredients selected by the user, so instead of a collection of Ingredients:
public ICollection<Ingredient> Ingredients { get; set; }
you have a collection of Ids (which is the property you are using as the value of the multi-select), for example:
public int[] SelectedIngredients { get; set; }
(I have renamed the property but that is not strictly needed, I have done it just for clarity)
As a suggestion, I would remove the default option value from that multi-select (The "Select the ingredients" option) and use a label or tooltip. Otherwise it may look like any other value from the list and you will have to deal with the scenario where the user selects that option, which is not a valid ingredient.
Even better, I would also use the #Model.ListBoxFor helper as that will let everybody know they are dealing with a multi-select. Otherwise (with the drop down helper) you may not realize it is a multi-select unless you look at the attributes. Something like:
#Html.ListBoxFor(m=>m.SelectedIngredients, new SelectList(Model.ListIngredients, "Id", "Description"))
Of course, these are just suggestions. You can happily Ignore them if they don't apply to your requirements!
As a final comment, it is possible to convert the posted values into Ingredient objects as you initially had in your view model. That would require you to write your own model binder and configure it for the Ingredient type. However you will only receive the id in the posted values, so you would have to retrieve the other properties (from the database probably) or you will have a collection of Ingredient objects where only the Id is populated. I would not go down this route unless you really need to.

After saving object using Entity Framework to MySQL the object id still shows as 0

I am using Entity Framework and have a connection to a MySQL database. The id column is set to use StoreGeneratedPattern Identity and the column in the database has been set to auto-increment. When I create a new object and save it to the database, the item posts correctly in the database. However, after saving, the id of the object in C# remains 0 rather than reflecting the value than was assigned by the database.
The section of code is given below:
Group newGroup = new Group("MyGroupName", "Active");
dbContext.Groups.Add(newGroup);
dbContext.SaveChanges();
int testId = newGroup.id;
Even though "newGroup" saves in the database with a database-assigned id, when I read the id (such as I do when reading testId) the id is still 0.
Based on this, I have tried adding
dbContext.Entry(newGroup).Reload();
after SaveChanges() and I have also tried (based on this and this) adding
var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
objectContext.Refresh(System.Data.Objects.RefreshMode.StoreWins, newGroup);
after SaveChanges() in an attempt to refresh the object (and thus the id) from the database, yet the problem remains. How can I get the id that was assigned by the database?
EDIT: Adding class definition for Group:
[Table("groups")]
public partial class Group
{
public Group()
{
this.user_groups = new HashSet<UserGroup>();
}
public long id { get; set; }
public string name { get; set; }
public string status { get; set; }
public System.DateTime created_at { get; set; }
public System.DateTime updated_at { get; set; }
public virtual ICollection<UserGroup> user_groups { get; set; }
}
Try decorating your id with the [Key] attribute.
It SHOULD be this attribute
[DatabaseGenerated(DatabaseGenerationOption.Identity)]
However, this SHOULD be the default.
The [Key] attribute, should be unnecessary since the column name Id is magical... Although this might only be the case when using the accepted naming convention for C#.
I wonder if it might be the long that your id property is typed, or possibly the naming convention... you could try naming it Id.
I'm having the same problem with my project. What I did for a work around was to order the table (group) by the ID descending and select the first or default record, then select the ID column.
var newID = dbcontext.Groups.OrderByDescending(x => x.id).FirstOrDefault().ID
You can then assign that to whatever you need and save changes again. I know it's an old thread but hopefully this helps. Seems like there should be a better way to do it...

Kendo Grid Get All Table Records

I am trying to get all of the records that are in a database, and download them to an Excel file. There are over 3000 records, but when I get the data from the Kendo Grid (I am successfully making it into JSON format), it is only showing the 25 records that I currently have displayed on the page.
I have Server Paging set to true, and like I said, my page size is 25. Is there some trick I can do to get all 3000+ records put into the JSON I am sending, or am I stuck just getting the 25 that are displayed currently on the page?
By design, you should make another call to get data to export to excel file. This will keep the page light weight.
But if you still wish to go ahead with loading all 3000 records every time, you can disable server paging and enable client side paging, so that you can see 25 records on UI, but you have 3000 records in response.
Again you will need to separate the DataSource from the grid so that the grid can be shared.
Based on your last comment:
If you are using MVC (ASP.NET) you can pass FilterContainer object as parameter to container to capture all the conditions to filter the data from database.
public class FilterContainer
{
public List<FilterDescription> Filters { get; set; }
public string Logic { get; set; }
}
public class FilterDescription
{
public string Operator { get; set; }
public string Field { get; set; }
public string Value { get; set; }
public List<FilterDescription> Filters { get; set; }
public string Logic { get; set; }
}
Build this structure in JavaScript to push the conditions from Js to filter the data.

Can I specify a discriminator column with a table-per-type mapping?

I have a class hierarchy that I want to map across several tables using Entity Framework 4.1 Code First. It's like table-per-type (TPT) but I also want a discrimator column.
The hierarchy looks something like:
public class Event
{
public Guid Id { get; set; }
public string Code { get; set; } // discriminator
public DateTime Date { get; set; }
}
public class Party : Event
{
public int AttendeeCount { get; set; }
}
public class BirthdayParty : Party
{
public int Age { get; set; }
}
public class WeddingParty : Party
{
public string Surname { get; set; }
}
This is a pretty weak example but I hope it makes sense. There'll be an "Events" table, a "Parties" table and a table for each kind of party. However, the discriminator column ("Code") will have a known value for each kind of event, like "BIRTH" for birthday parties or "WEDDING" for wedding parties.
The idea is that if I query for just birthday parties on a given date, EF would know to add Code = 'BIRTH' to my query instead of doing a bunch of UNIONs and JOINs to work out which rows it needs.
I map my lowest-level classes like this:
var bd = modelBuilder.Entity<BirthdayParty>();
bd.ToTable("BirthdayParties");
bd.Property(p => p.Age).HasColumnName("BirthdayAge");
I now need to specify the discriminator value in there somehow. I've tried this:
modelBuilder.Entity<Event>().Map<BirthdayParty>(cfg =>
{
cfg.Requires("Code").HasValue("BIRTH");
});
... but that complains that I haven't specified the table name inside the call to Map. So I tried moving the ToTable call into there:
var bd = modelBuilder.Entity<BirthdayParty>();
bd.Property(p => p.Age).HasColumnName("BirthdayAge");
modelBuilder.Entity<Event>().Map<BirthdayParty>(cfg =>
{
cfg.Requires("Code").HasValue("BIRTH");
cfg.ToTable("BirthdayParties");
});
... and now it thinks I want a "Code" column in the "BirthdayParties" table, which is not correct. I've already told it that the "Code" column is in the "Events" table.
Is this even possible? Can I combine the use of a discriminator column with a table-per-type mapping?
Unfortunately this is not supported. Discriminator column can be used only in TPH. TPT differs entity types by mapped tables and it always produces those terrible queries. It could be nice feature so perhaps suggestion on Data UserVoice would make it implemented one day.
Update
There is already a suggestion on user voice for this titled "Discriminator column support in TPT inheritance".
I did an override on SaveChanges to accomplish something similar. I simply added an attribute onto the abstract class called Descriminator and set it based on the Concrete Class Name anytime something new is added.
public class MyContext : DbContext
{
public override int SaveChanges()
{
foreach (var item in ChangeTracker.Entries().Where(x=>x.Entity is MyAbstractClass && x.State == EntityState.Added))
{
((MyAbstractClass)item.Entity).Descriminator = item.Entity.GetType().Name;
}
return base.SaveChanges();
}
}