OneToOne mapping with NHibernate and Breeze - breeze

Is it possible to make that kind of mapping work with breeze and NHibernate:
public class PeopleMap: BaseMapping<People>
{
public PeopleMap()
{
this.Property(x => x.FirstName);
this.Property(x => x.LastName);
}
}
public class PersonMap : JoinedSubclassMapping<Person>
{
public PersonMap()
{
this.Key(p=>p.Column("ID"));
this.Property(x => x.FirstName);
this.Property(x => x.LastName);
this.Property(x => x.InfoId, map =>
{
map.Insert(false);
map.Update(false);
}
);
this.ManyToOne(x => x.Info, map =>
{
map.Cascade(Cascade.All);
map.Column("InfoId");
});
}
public class PersonInfoMap : BaseMapping<PersonInfo>
{
public PersonInfoMap()
{
this.Property(x => x.Extra);
this.OneToOne(x => x.Person, map =>
{
map.Constrained(true);
map.PropertyReference(p => p.Info);
});
}
}
There is a table per subclass inheritance between people and person. The goal is to make a one to one association between person and personinfo. The mapping works fine in NHibernate. The metadata are generated and queries can be done. The only problem is I can't do a save.
var d = breezeService.manager.createEntity('Person',
{
FirstName: 'Laurent',
LastName: 'Nullens'
});
var l = breezeService.manager.createEntity('PersonInfo',
{
Extra: 'First data',
Person: d
});
d.Info = l;
The result is an exception because the Person entity is saved before the PersonInfo(foreign key exception). I saw in the samples a one to one with Order and InternationlOrder but in that sample both entities share the same primary key.
Is it possbile or is there any workaround like in the Order/InternationalOrder sample?

Have you looked at the breezjs NHibernate sample?
Please do ... and then report back if you can't find what you're looking for.

Related

How can I change default ASP.NET Identity table names in .NET CORE?

I've started with .NET Core, in MVC 5 I changed default table names for example: AspNETUsers to Users in this way and it worked perfectly:
In IdentityModels Class I dded:
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>().ToTable("Users").Property(p => p.Id).HasColumnName("UserId");
modelBuilder.Entity<ApplicationUser>().ToTable("Users").Property(p => p.Id).HasColumnName("UserId");
modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles");
modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins");
modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims");
modelBuilder.Entity<IdentityRole>().ToTable("Roles");
}
But it does not work in ASP.NET CORE (MVC 6).
Can Anyone help me?
Thanks a lot.
-To change the names of those tables ( IdentityUserRole<Tkey>, IdentityUserToken<Tkey>, IdentityRoleClaim<Tkey>, IdentityUserClaim<Tkey>, IdentityUserLogin<Tkey>) you have to specify the type of TKey(The type used for the primary key ) which is string(GUID) by default even if you didn't change it.
-If you want to change the primary key from GUID to int https://medium.com/#goodealsnow/asp-net-core-identity-3-0-6018fc151b4
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
builder.Entity<ApplicationUser>(entity =>
{
entity.ToTable(name: "User");
});
builder.Entity<IdentityRole>(entity =>
{
entity.ToTable(name: "Role");
});
builder.Entity<IdentityUserRole<string>>(entity =>
{
entity.ToTable("UserRoles");
//in case you chagned the TKey type
// entity.HasKey(key => new { key.UserId, key.RoleId });
});
builder.Entity<IdentityUserClaim<string>>(entity =>
{
entity.ToTable("UserClaims");
});
builder.Entity<IdentityUserLogin<string>>(entity =>
{
entity.ToTable("UserLogins");
//in case you chagned the TKey type
// entity.HasKey(key => new { key.ProviderKey, key.LoginProvider });
});
builder.Entity<IdentityRoleClaim<string>>(entity =>
{
entity.ToTable("RoleClaims");
});
builder.Entity<IdentityUserToken<string>>(entity =>
{
entity.ToTable("UserTokens");
//in case you chagned the TKey type
// entity.HasKey(key => new { key.UserId, key.LoginProvider, key.Name });
});
}
Try to change binding to
builder.Entity<ApplicationUser>(entity =>
{
entity.ToTable(name:"Users");
entity.Property(e => e.Id).HasColumnName("UserId");
});
A complete list for ASP.Net Core 2/2.1, based on #ahmed-al-jabry 's answer.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Override default AspNet Identity table names
modelBuilder.Entity<User>(entity => { entity.ToTable(name: "Users"); });
modelBuilder.Entity<IdentityRole>(entity => { entity.ToTable(name: "Roles"); });
modelBuilder.Entity<IdentityUserRole<string>>(entity => { entity.ToTable("UserRoles"); });
modelBuilder.Entity<IdentityUserClaim<string>>(entity => { entity.ToTable("UserClaims"); });
modelBuilder.Entity<IdentityUserLogin<string>>(entity => { entity.ToTable("UserLogins"); });
modelBuilder.Entity<IdentityUserToken<string>>(entity => { entity.ToTable("UserTokens"); });
modelBuilder.Entity<IdentityRoleClaim<string>>(entity => { entity.ToTable("RoleClaims"); });
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>(b =>
{
b.ToTable("ANYName");
});
modelBuilder.Entity<IdentityUserRole<string>>(b =>
{
b.ToTable("ANYName");
});
modelBuilder.Entity<IdentityRole<string>>(b =>
{
b.ToTable("ANYName");
});
modelBuilder.Entity<IdentityUserClaim<string>>(b =>
{
b.ToTable("ANYName");
});
modelBuilder.Entity<IdentityUserLogin<string>>(b =>
{
b.ToTable("ANYName");
});
modelBuilder.Entity<IdentityUserToken<string>>(b =>
{
b.ToTable("ANYName");
});
modelBuilder.Entity<IdentityRole>(b =>
{
b.ToTable("ANYName");
});
modelBuilder.Entity<IdentityRoleClaim<string>>(b =>
{
b.ToTable("ANYName");
});
modelBuilder.Entity<IdentityUserRole<string>>(b =>
{
b.ToTable("ANYName");
});
}
Add this method in ApplicationDbContext and add-migration to create changes and then update database to save changes.
Just for documentation purpose, for the one who comes to this post on the years anyears on the future, (like me XD), The answer to the question:
How can I change default ASP.NET Identity table names in .NET CORE?
Can be solved as this
//Repeat with each table
builder.Entity<ApplicationUser>(entity =>
{
entity.ToTable(name:"Users");
entity.Property(e => e.Id).HasColumnName("UserId");
});
Or can be solved like this
modelBuilder.Entity<IdentityUser>().ToTable("MyUsers").Property(p => p.Id).HasColumnName("UserId");
modelBuilder.Entity<ApplicationUser>().ToTable("MyUsers").Property(p => p.Id).HasColumnName("UserId");
modelBuilder.Entity<IdentityUserRole>().ToTable("MyUserRoles");
modelBuilder.Entity<IdentityUserLogin>().ToTable("MyUserLogins");
modelBuilder.Entity<IdentityUserClaim>().ToTable("MyUserClaims");
modelBuilder.Entity<IdentityRole>().ToTable("MyRoles");
But you can simplyfied with this method given by Alexandru Bucur on his blog and tested on netcore 2.2
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
var table = entityType.Relational().TableName;
if (table.StartsWith("AspNet"))
{
entityType.Relational().TableName = table.Substring(6);
}
};
But this it's not longger support on netcore > 2.2, so, I need to fix it and this is the functional way on NetCore > 2.2
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
var tableName = entityType.GetTableName();
if (tableName.StartsWith("AspNet"))
{
entityType.SetTableName(tableName.Substring(6));
}
}
Choose what you prefeer and enjoy it, HappyCoding
There are further 2 steps required to apply changes:
Apply Add-Migration
Update-database
I am adding a second answer, because many people will hit this when trying to change table names in .NET core 1, 2, 3 and .NET 5
The process is pretty straightforward and well explained in the docs.
For those needing quick fix:
Inherit all your models which you want to change( default Microsoft authorization comes with 7 models ). For example changing AspNetUsers to User and AspNetRoles to Role you can do the following in your existing models:
public partial class User : IdentityUser<int>
{
// code
}
public partial class Role : IdentityRole<int>
{
// code
}
In this example I am changing the primary key type also because the default is nvarchar.
In your context inherit from IdentityDbContext and use the same type as argument:
public class AppDbContext : IdentityDbContext<User, Role, int>
{
// code
}
Next we have to update ConfigureServices in StartUp to use the new User class:
services.AddDefaultIdentity<User, Role>()
.AddEntityFrameworkStores<AppDbContext>();
Then if want need you migrate to update/create database. Depends if this is a new or old project.
Note: If you are currently using authentication in your project like UserManager or SignInManager you have to change their generic arguments to the new ones like so:
SignInManager<User>
UserManager<User>
Hope that helps :)
To update default table names IdentityModels Class MVC
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>().ToTable("Users").HasKey(x => x.Id);
modelBuilder.Entity<ApplicationUser>().ToTable("Users").HasKey(x => x.Id);
modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles").HasKey(x => x.RoleId);;
modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins").HasKey(x => x.UserID);;
modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims").HasKey(x => x.Id);;
modelBuilder.Entity<IdentityRole>().ToTable("Roles").HasKey(x => x.Id);;
}
For MVC5 IdentityModels
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
builder.Entity<IdentityUser>().Table("Users").Key(x => x.Id);
builder.Entity<ApplicationUser>().Table("Users").Key(x => x.Id);
builder.Entity<IdentityUserRole>().Table("UserRoles").Key(x => x.RoleId); ;
builder.Entity<IdentityUserLogin>().Table("UserLogins").Key(x => x.UserId); ;
builder.Entity<IdentityUserClaim>().Table("UserClaims").Key(x => x.Id); ;
builder.Entity<IdentityRole>().Table("Roles").Key(x => x.Id); ;
}
There is one extra note :
I customized all of my identity tables name but it didn't apply. base on Microsoft reference you have to use base.OnModelCreating(builder); before your customization
To change the names of tables and columns, call base.OnModelCreating. Then, add configuration to override any of the defaults. For example, to change the name of all the Identity tables:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>(b =>
{
b.ToTable("MyUsers");
});
modelBuilder.Entity<IdentityUserClaim<string>>(b =>
{
b.ToTable("MyUserClaims");
});
modelBuilder.Entity<IdentityUserLogin<string>>(b =>
{
b.ToTable("MyUserLogins");
});
modelBuilder.Entity<IdentityUserToken<string>>(b =>
{
b.ToTable("MyUserTokens");
});
modelBuilder.Entity<IdentityRole>(b =>
{
b.ToTable("MyRoles");
});
modelBuilder.Entity<IdentityRoleClaim<string>>(b =>
{
b.ToTable("MyRoleClaims");
});
modelBuilder.Entity<IdentityUserRole<string>>(b =>
{
b.ToTable("MyUserRoles");
});
}
In Entity Framework Core Version 6 this works fine:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
foreach (var entity in builder.Model.GetEntityTypes())
{
// Replace table names
entity.SetTableName(entity.GetTableName().ToSnakeCase());
}
}

How to make Sorting and Filtering working for viewmodel column in InLine editing of Kendo UI MVC grid signalR?

Sorting and Filtering are not working on the column bound with ViewModel entity. It is working fine with other columns.
Sample Grid Code:
#(Html.Kendo().Grid<abc.Models.ShippingViewModel>()
.Name("ShippingGrid")
.Columns(c =>
{
c.Bound(m => m.Id).Hidden();
c.Bound(m => m.LocationViewModel)
.ClientTemplate("#=LocationViewModel.LocationName#")
.Title("Pickup Location")
.HeaderHtmlAttributes(new { #title = "Pickup Loactions" });
c.Bound(m => m.UnitsShipped)
.HtmlAttributes(new { style = "text-align:right" })
.HeaderHtmlAttributes(new { title = "Units Shipped", style = "text-align: right" });
Model:
public class InHouseShippingViewModel
{
[ScaffoldColumn(false)]
public int Id { get; set; }
[Required]
[UIHint("ShippingLocationEditor")]
public LocationViewModel LocationViewModel { get; set; }
[Required]
[Display(Name = "Units Shipped")]
[UIHint("ComanexIntegerEditor")]
[DisplayFormat(DataFormatString = GlobalVaribleDeclarations.displayFormatForInteger)]
public int UnitsShipped { get; set; }
}
Hub/Controller code:
public IEnumerable<ShippingViewModel> Shipping_Read()
{
var queryResult = ShippingRepository.Shipping_Read();
return queryResult;
}
Here Sorting is working fine on "UnitShipped" column whereas it is not working on "LocationViewModel" column. If I use c.Bound(m => m.LocationViewModel.LocationName), sorting & filtering are working fine but then I am not able to get the DropDownEditor for the this column when editing a record. I am using "InLine" editing here.
I have tested this with "PopUp" editing and everything working fine. I would like to achieve this with "InLine" editing though.
Please advise what should I do to achieve "InLine" editing with Cascading dropdown and Sorting all together. thanks!
there is a mix of things to do. First for filtering etc you need to use the datasourcerequest parameter as in normal ajax calls but then you will find out that sorting does not work.
public DataSourceResult Read(MyDataSourceRequest request)
{
}
this does not work since the kendo regular use 'sorts' for passing a collection of sort and this collection is passed by the signalr datasource as 'sort' (no s). you will have to use the dynamic linq nuget package which has a custom datasource request that will work with signalr. Please copy their code in your solution for the custom datarequest object and the slightly todatasourceresult syntax.
http://www.telerik.com/forums/problems-with-grid-using-signalr-and-serverfiltering-sorting-and-paging
relaying information needs a wrap in datasourceresult as well
Clients.Others.update(WrapInDataSourceResult(item));
public DataSourceResult WrapInDataSourceResult(EmployeeViewModel item)
{
return new DataSourceResult
{
Data = new[]
{
item
}
};
}
also you need to activate server side options serverpaging(true) etc
.SignalR()
.AutoSync(true)
.Sort(c => c.Add(e => e.FullName).Ascending())
.ServerAggregates(true)
.ServerPaging(true)
.ServerSorting(true)
.ServerGrouping(true)
and in the schema
.Schema(schema => schema
.Data("Data")
.Total("Total")
.Aggregates("Aggregates")
.Groups("Groups")
.Model(model =>
{
model.Id(m => m.EmployeeId);
})

IQueryable to IEnumerable

public IEnumerable<Temp_Order> Get_Temp(string id)
{
//List<Temp_Order> data = new List<Temp_Order>();
IEnumerable<Temp_Order> data = db.Temp_Order
.Join(db.Items,
t_id => t_id.ItemId,
I_id => I_id.ItemId,
(t_id, I_id) => new { t_id.Quantity, I_id.ItemName })
.Where(x => x.ItemName == id);
return data;
}
In this method I want IEnumerable<Temp_Order>. So I will use this in controller and return to the view.
I'm getting this error:
Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Collections.Generic.IEnumerable'. An explicit conversion exists (are you missing a cast?) E:\WORK\Projects\RMS_Live\RMS_Live\Models\Order.cs
The Join is converting your query to an IEnumerable of an anonymous type. Add a Select on the end to cast is back to Temp_Order:
public IEnumerable<Temp_Order> Get_Temp(string id)
{
//List<Temp_Order> data = new List<Temp_Order>();
IEnumerable<Temp_Order> data = db.Temp_Order
.Join(db.Items, t_id => t_id.ItemId, I_id => I_id.ItemId, (t_id, I_id) => new { t_id.Quantity, I_id.ItemName })
.Where(x => x.ItemName == id)
.Select(a => new Temp_Order
{
ItemName = a.ItemName,
Property2 = a.Property2,
//snip
});
return data;
}
EDIT:
You indicate in the comments that you want all properties from both Temp_Order and Item which means you need another class. You can get away without creating another class, but it's much simpler in the long run. So first make your class, 2 ways spring to mind, you either replicate all the properties you need or just return the 2 objects, I'll use the latter:
public class OrderItem
{
public Temp_Order Temp_Order { get; set; }
public Item Item { get; set; }
}
Now your function becomes this:
public IEnumerable<OrderItem> Get_Temp(string id)
{
IEnumerable<OrderItem> data = db.Temp_Order
.Join(db.Items,
t_id => t_id.ItemId,
I_id => I_id.ItemId,
(t_id, I_id) => new OrderItem
{
Temp_Order = t_id,
Item = I_id
})
.Where(x => x.ItemName == id);
return data;
}
And in your view, make sure you set the model type to IEnumerable<OrderItem> and you can access all the properties like this:
#Model.Temp_Order.ItemName

NHibernate and HasMany mapping

i have trivial mapping for two entities: poll and polloption
Poll:
public class PollMap : ClassMap<Poll>
{
public PollMap() {
Id(x => x.Id);
Map(x => x.Content);
HasMany(x => x.PollOptions).Cascade.All();
}
}
PollOption:
public class PollOptionMap : ClassMap<PollOption>
{
public PollOptionMap() {
Id(x => x.Id);
Map(x => x.Content);
References(x => x.Poll);
}
}
in test code im trying to remove the first polloption of poll entity
Test code:
[Transaction]
public ActionResult Add() {
var poll = new Poll() {
Content = "poll",
PollOptions = new List<PollOption>() {
new PollOption(){
Content="PollOption#1"
},
new PollOption(){
Content="PollOption#2"
}
}
};
GetSession.Save(poll);
return Content("Added");
}
[Transaction]
public ActionResult Removed() {
var poll = GetSession.Query<Poll>().FirstOrDefault();
poll.PollOptions.RemoveAt(0);
GetSession.Update(poll);
return Content("Updated");
}
when the remove action fired it not deleting polloption from db instead it set null in my foreign key :(
ps. google not helped
Cascade.All() only deletes the child object if the parent is deleted. If you want the childs to get deleted when they are removed from the collection, you need Cascade.AllDeleteOrphan().
Additional note: You also have to mark one side of your bidirectional association as Inverse(). More info about that here: http://nhibernate.info/doc/nh/en/index.html#collections-bidirectional

Architecture abstraction problem in Repository ASP.NET MVC

I'm working with MVC ASP.NET 3.5 SP1 on VS2008.
I'm looking for a way to abstract this three methods I have in my Users repository.
public User GetUser(Log log)
{
return db.Users.FirstOrDefault(u => u.Logs.Any(l => l.id.Equals(log.id)));
}
public User GetUser(Product product)
{
return db.Users.FirstOrDefault(u => u.Products.Any(pr => pr.id.Equals(product.id)));
}
public User GetUser(Photo photo)
{
return db.Users.FirstOrDefault(u => u.Photos.Any(ph => ph.id.Equals(photo.id)));
}
My DB.edmx contains the models
User [id, username, ...]
Product [id, name, ...]
Photo [id, name, ...]
Log [id, data, ...]
Is it possible to have only ONE method for all of these (and future) methods based upon model.id search?
public User GetUser(Expression<Func<User, bool>> restriction)
{
return db.Users.Where(restriction).FirstOrDefault();
}
Now use it:
var u = Repository.GetUser(u => u.Logs.Any(l => l.id.Equals(log.id)));
You can also use MS DynamicQuery:
using System.Linq.Dynamic;
//...
public User GetUser(string propertyName, int id)
{
var restriction = propertyName + ".Any(id = #0)";
return db.Users.Where(restriction, id).FirstOrDefault();
}
var u = Repository.GetUser("Logs", log.id);
I may not have the syntax quite correct, but you get the idea.
If all the associated entities (Log, Product and Photo) will be searched by a common property (id INT) then maybe you could try something like this...
First, create an interface:
public interface IUserAssociation
{
int id { get; }
}
Then each of the three classes would implement this interface like so:
public partial class Product : IUserAssociation
{
}
The the GetUser method would look like so:
public User GetUser<T>(T entity) where T : IUserAssociation
{
var type = typeof(T);
if (type == typeof(Log))
{
return db.Users.FirstOrDefault(u => u.Logs.Any(l => l.id.Equals(entity.id)));
}
else if (type == typeof(Product))
{
return db.Users.FirstOrDefault(u => u.Products.Any(pr => pr.id.Equals(entity.id)));
}
else if (type == typeof(Photo))
{
return db.Users.FirstOrDefault(u => u.Photos.Any(ph => ph.id.Equals(entity.id)));
}
else
{
throw new ArgumentException();
}
}
Then you should be able to call GetUser and pass it a Log, Photo or Product entity from one method. It is not very elegant but would work for this specific situation.
I like Craig's solution better but I'd suggest this:
Repository.GetUser(u => u.Logs, log);
Which will be possible if all your entities derive from
public interface IEntity { public int Id { get; } }
Then method will be like
public User GetUser<T, Y>(Func<T, IList<Y>> getlist, Y sample)
where T: IEntity
where Y: IEntity
{
return db.Users.Select(x => getlist(x).Any(y => y.Id == sample.Id)).FirstOrDefault();
}
Also if we take idea of S#arp Architecture that if entity1.Id == entity2.Id (for persistent entities) then Equals(entity1, entity2) - we can use getlist(x).Contains(sample).

Resources