Entity Framework code first generating compound primary key not working - entity-framework-5

As per all the examples I see, this code should generate a compound primary key, but for some reason it isn't in my case.
public abstract class MyBase
{
[Key, Column(Order = 0)]
public int Id { get; set; }
}
public abstract class MyClass : MyBase
{
[Key, Column(Order = 1)]
public AnotherClass AnotherClass { get; set; }
}
public abstract class AnotherClass : MyBase
{
}
I am expecting the MyClass table to have a compound foreign key consisting of Id and AnotherClass_Id.

I solved it by doing Add-Migration -Force and that redid the scaffolding of my migration, then I did Update-Database.
But I have found that after doing Add-Migration -Force it's useful to look at the generated migration file and see if the effect is what I intended before updating the database.

Related

Mapping int (Id) to Model instance

I often have Models and Dtos like this:
// DTO class
public class OrderDto
{
public int Id { get; set; }
public DateTime Date { get set; }
public int ProductId { get; set; }
// ...
}
// Model class
public class Order : BaseObject
{
public DateTime Date { get set; }
public Product Product { get; set; }
// ...
}
// Model class
public class Product : BaseObject
{
// ...
}
In order to map my OrderDto to the Order class I have to configure AutoMapper for this particular "association" like so:
CreateMap<OrderDto, Order>()
.ForMember(m => m.Product, d => d.ResolveUsing((d, m) =>
{
return m.Session.GetObjectByKey<Product>(dto.ProductId);
}))
This is quite cumbersome to do this for each case like this. Therefore I was looking into generalizing this behaviour by using a custom TypeConverter class:
public class IntBaseObjectTypeConverter : ITypeConverter<int, BaseObject>
{
private UnitOfWork uow;
// ...
public BaseObjectConvert(int source, BaseObject destination, ResolutionContext context)
{
return uow.Session.GetObjectByKey(typeof(destination), source);
}
}
However, this will fail of course if the destination is null. Unfortunately the ResolutionContext does not give me any clue about the specific type of the destination property.
Now my question is, if there is another way to achieve with AutoMapper what I would like to do?
Please note that I am not using Entity Framework which of course would solve this issue on the model level with foreign key and navigational properties. I use XPO from DevExpress which does not allow foreign key and navigational properties like in Entity Framework.

Map properties by nameing convention

I am using automapper to map some objects between the database and another representation.
The entity looks something like
public class MyEntity {
public int Id { get; set; }
public Guid RowId { get; set; }
}
public class MyObject {
public Guid Id { get; set; }
}
As you can see, the names and types are unaligned.
Since I got many Entities and Objects, I'd rather not CreateMap<A, B>().ForMember(d => d.Id, mex => mex.MapFrom(s => s.RowId));.
To not having to do the above Convention:
AddMemberConfiguration()
.AddMember<NameSplitMember>()
.AddName<ReplaceName>(_ => _.AddReplace("RowId", "Id"));
This does not what I suspected it to do and I was not able to figure out, how to use the ReplaceName Convention.
So I'd like to hear ideas about how to map that types.
MyEntity and MyObject both are base types, so I could also use that.
What I'm trying to archieve in pseudo-code:
if(source is MyEntity && target is MyObject)
{
target.Id = source.RowId;
}
ForAllMembers
On recommendation of #lucian-bargaoanu I tried looking into ForAllMembers.
I did the following in the MapperProfile:
public class MapperProfile : Profile {
public MapperProfile() {
ForAllMaps(MapEntityBaseId);
}
protected void MapEntityBaseId(TypeMap map, IMappingExpression mex)
{
if (!map.SourceType.IsSubclassOf(typeof(EntityBase)))
return;
if (!map.DestinationType.IsSubclassOf(typeof(MyObject)))
return;
mex.ForMember("Id", opt => opt.MapFrom("RowId"));
}
}
also the debugger hints me, that ForAllMember is executed as expected, it still fails the mapping.
I created a GIST for the ForAllMembers: https://gist.github.com/anonymous/511a1b69b795aa2bc7e7cd261fcb98b1

"No Key Defined" error message, when creating a view for a view model

Currently I am creating a project following 'MVC Music Store' tutorial, when come to create a view for "ShoppingCartViewModel", it always shows the error that tells me that there is no Key definied.
The error message is: Entity type'ShoppingCartViewModel' has no key defined....
Here is the original code from the tutorial:
namespace MyMVStore.ViewModels
{
public class ShoppingCartViewModel
{
public List<Cart> CartItems { get; set; }
public decimal? CartTotal { get; set; }
}
}
Here is what I updated:
//[NotMapping]
namespace MyMVStore.ViewModels
{
public class ShoppingCartViewModel
{
[Key] //my code
public int Id { get; set; } // my code
public List<Cart> CartItems { get; set; }
public decimal? CartTotal { get; set; }
}
}
I put [Key] and Id to the model, seems not working. I also tried to add [Notmapping], it doesn't work either. The error massage still showing up when I tried to create the view for this model.
All you need to do is remove the DataContext class from the dropdown. It's an editable dropdown, so you can just highlight it and delete it.
It works fine after you do that.
You most likely have declared DbSet in your context class, which is associated with EF. Remove the declaration to make it a non-table model.

ServiceStack ORMLite how to not serialize list

I don't know how to store collection (Comments) in separate table.
By default comments are serialized and stored in SomeClass table as column Comments.
[{Id:0,CreateDate:2013-09-12T14:28:37.0456202+02:00,,SomeClassID:1,CommentText:"coment text",}]
Is there any way to save it in separate tables?
public class SomeClass {
[AutoIncrement]
public int Id { get; set; }
public string Title { get; set; }
List<Comment> comments = new List<Comment>();
public List<Comment> Comments {
get { return comments; }
set { comments = value; }
}
}
public class Comment {
[AutoIncrement]
public int Id { get; set; }
[References(typeof(SomeClass))]
public int SomeClassID { get; set; }
[StringLength(4000)]
public string CommentText { get; set; }
}
I don't think ORMLite supports serializing to multiple tables. 1 table = 1 class so the comments will be stored as a Blob field in the SomeClass table.
If you need to store them in separate tables you will have to save the comments separately and have a foreign key reference back to the id of the SomeClass table.

Breeze doesn't expand TPH entities correctly

Breeze doesn't expand TPH entities correctly.
When using expand in breeze if you are using TPH expand will only work for the first entity, the others properties will be null. If I change the entity not to use inheritances it works fine. I've also tested returning each entity separately in an expand query that also worked fine.
//client side code
var getResidentById = function (id, obs) {
var query = EntityQuery.from('Residents')
.where('id', '==', id)
.expand('user, currentUnit, leases, leases.unit, leases.leaseStatus');
return manager.executeQuery(query).then(function (data) {
if (obs) {
obs(data.results[0])
}
}, queryFailed);
};
//Controler Endpoint
[HttpGet]
public IQueryable<Resident>
{
return _context.Context.UserDetails.OfType<Resident>();
}
//Model
public class UserDetail : EntityBase<int>, IArchivable, IHasPhoto, IDeactivatableEntity, IUpdatable
{
public bool IsArchived { get; set; }
public int LastUpdatedById { get; set; }
public UserProfile LastUpdatedBy { get; set; }
public DateTimeOffset LastUpdatedDate { get; set; }
public string PhotoUri { get; set; }
public bool IsInactive { get; set; }
}
public abstract class UserBelongsToApartmentComplex : UserDetail, IBelongsToApartmentComplex
{
public int ApartmentComplexId { get; set; }
public virtual ApartmentComplex ApartmentComplex { get; set; }
public virtual bool IsInSameComplexAs(IRelatedToApartmentComplex otherEntity)
{
return ApartmentComplexId == otherEntity.ApartmentComplexId;
}
}
public class Staff : UserBelongsToApartmentComplex
{
public string Title { get; set; }
}
public class Admin : UserDetail
{
public string AccessLevel { get; set; }
}
public class Resident : UserBelongsToApartmentComplex
{
public string Pets { get; set; }
public bool HasInsurance { get; set; }
public virtual IList<Lease> Leases { get; set; }
public int? CurrentUnitId { get; set; }
public virtual Unit CurrentUnit { get; set; }
public Resident()
{
Leases = new List<Lease>();
}
}
//response data from sever from endpoint public IQueryable Residents()
[{"$id":"1","$type":"RadiusBlue.Core.Models.Resident, RadiusBlue.Core","Pets":"Sadie, a westie","HasInsurance":false,"Leases":[{"$id":"2","$type":"RadiusBlue.Core.Models.Lease, RadiusBlue.Core","Start":"2012-05-23T00:00:00.000","End":"2013-05-23T00:00:00.000","UnitId":2,"Unit":{"$id":"3","$type":"RadiusBlue.Core.Models.Unit, RadiusBlue.Core","Building":"B","Floor":2,"ModelName":"Tera","RentAmount":2500.00,"NumberOfBeds":1,"NumberOfBaths":3,"UnitName":"102A","IsInactive":true,"Inhabitants":[],"ApartmentComplexId":1,"ApartmentComplex":{"$id":"4","$type":"RadiusBlue.Core.Models.ApartmentComplex, RadiusBlue.Core","Name":"The Stratford","StreetAddress":"100 S Park Ave","City":"Winter Park","StateId":10,"ZipCode":"32792","PropertyManagementCompanyId":1,"IsInactive":false,"TimeZoneId":"Eastern Standard Time","TimeZone":{"$id":"5","$type":"System.TimeZoneInfo, mscorlib","Id":"Eastern Standard Time","DisplayName":"(UTC-05:00) Eastern Time (US & Canada)","StandardName":"Eastern Standard Time","DaylightName":"Eastern Daylight Time","BaseUtcOffset":"-PT5H","AdjustmentRules":[{"$id":"6","$type":"System.TimeZoneInfo+AdjustmentRule, mscorlib","DateStart":"0001-01-01T00:00:00.000","DateEnd":"2006-12-31T00:00:00.000","DaylightDelta":"PT1H","DaylightTransitionStart":{"$id":"7","$type":"System.TimeZoneInfo+TransitionTime, mscorlib","TimeOfDay":"0001-01-01T02:00:00.000","Month":4,"Week":1,"Day":1,"DayOfWeek":"Sunday","IsFixedDateRule":false},"DaylightTransitionEnd":{"$id":"8","$type":"System.TimeZoneInfo+TransitionTime, mscorlib","TimeOfDay":"0001-01-01T02:00:00.000","Month":10,"Week":5,"Day":1,"DayOfWeek":"Sunday","IsFixedDateRule":false}},{"$id":"9","$type":"System.TimeZoneInfo+AdjustmentRule, mscorlib","DateStart":"2007-01-01T00:00:00.000","DateEnd":"9999-12-31T00:00:00.000","DaylightDelta":"PT1H","DaylightTransitionStart":{"$id":"10","$type":"System.TimeZoneInfo+TransitionTime, mscorlib","TimeOfDay":"0001-01-01T02:00:00.000","Month":3,"Week":2,"Day":1,"DayOfWeek":"Sunday","IsFixedDateRule":false},"DaylightTransitionEnd":{"$id":"11","$type":"System.TimeZoneInfo+TransitionTime, mscorlib","TimeOfDay":"0001-01-01T02:00:00.000","Month":11,"Week":1,"Day":1,"DayOfWeek":"Sunday","IsFixedDateRule":false}}],"SupportsDaylightSavingTime":true},"Users":[{"$ref":"1"}],"Groups":[],"IsArchived":false,"ApartmentComplexId":1,"Id":1},"Id":2},"ResidentId":3,"Resident":{"$ref":"1"},"LeaseStatusId":4,"LeaseStatus":{"$id":"12","$type":"RadiusBlue.Core.Models.LeaseStatus, RadiusBlue.Core","Description":"Lost","Id":4},"Id":1},{"$id":"13","$type":"RadiusBlue.Core.Models.Lease, RadiusBlue.Core","Start":"2013-05-24T00:00:00.000","End":"2014-05-24T00:00:00.000","UnitId":1,"Unit":{"$id":"14","$type":"RadiusBlue.Core.Models.Unit, RadiusBlue.Core","Building":"A","Floor":2,"ModelName":"Aqua","RentAmount":2000.00,"NumberOfBeds":2,"NumberOfBaths":1,"UnitName":"101A","IsInactive":true,"Inhabitants":[{"$ref":"1"}],"ApartmentComplexId":1,"ApartmentComplex":{"$ref":"4"},"Id":1},"ResidentId":3,"Resident":{"$ref":"1"},"LeaseStatusId":1,"LeaseStatus":{"$id":"15","$type":"RadiusBlue.Core.Models.LeaseStatus, RadiusBlue.Core","Description":"Active","Id":1},"Id":2}],"CurrentUnitId":1,"CurrentUnit":{"$ref":"14"},"ApartmentComplexId":1,"ApartmentComplex":{"$ref":"4"},"Id":3,"User":{"$id":"16","$type":"RadiusBlue.Core.Models.UserProfile, RadiusBlue.Core","UserName":"vjiawon#gmail.com","FirstName":"Vishal","LastName":"Jiawon","Age":27,"PhoneNumber":"123 456 7890","IsInactive":false,"UserDetail":{"$ref":"1"},"GroupMembers":[],"MaintenanceRequests":[],"Id":3},"IsArchived":false,"LastUpdatedById":1,"LastUpdatedDate":"0001-01-01T00:00:00.000+00:00","IsInactive":false,"CreatedById":1,"CreatedDate":"0001-01-01T00:00:00.000+00:00"}]
I do not doubt that there is a bug in BreezeJS somewhere.
I can report that, at least as of v.1.3.4, Breeze can expand multiple navigation properties of a TPH class ... and not just on the first entity returned.
I just modified the "can navigate to AccountType eagerly loaded with expand" test in inheritanceTests.js in DocCode so that (a) it also expands the Status navigation and (b) the tests are performed on the 3rd entity returned rather than the 1st.
The query is something like this:
var em = newEm(); // clean, empty EntityManager
return EntityQuery.from('bankRootTPHs').take(3)
.expand('AccountType, Status'))
.using(em).execute().then(success).fail(handleFail);
...
function success(data) {
var entity = data.results[data.results.length-1]; // get the last one (the 3rd)
var type = data.query.entityType.shortName;
if (!entity) {
ok(false, "a query failed to return a single " + type);
}
// more tests
// I just set a breakpoint and inspected
// entity.accountType() and entity.status()
// Both returned the expected related entities
}
I see that both the related AccountType and the related Status are available from the entity.
So something else is wrong.
Questions about your Example
First I am compelled to observe that you have a lot of expands. I count 5 related entities. That can hurt performance. I know we're not talking about that but I'm calling it out.
Second, the super class UserDetail is concrete but the intermediate derived class UserBelongsToApartmentComplex is abstract. You have inheritance class hierarchies that go concrete/abstract/concrete. The queried type, Residents is one such class. And a class at every level maps to the "UserDetail" table, yes?
I'm pretty sure we didn't test for that scenario ... which is pretty uncommon. I wasn't even sure that worked! For now I have to take your word for it that EF allows such a construct.
It would seem that BreezeJS is confused about it. We'll take a look.

Resources