CreateUserAndAccount method - SimpleMembership Provider - mysql

I have 2 questions:
Why am I getting that exception? I want to create a row in my User Table (it has 6 columns: Name, Role, Email, Group, Id, SoftwareVersion) and in the Membership table. The primary key is the pair Id-SoftwareVersion. The code:
code
What's wrong?
Is it possible add more row (with CreateUserAndAccount) by changing the id? Right? Example: try to add a row with "Administrator" as UserName when an entry already exists in the DB with the same name (but I remember the primary key is the pair Id-SoftwareVersion).
My User class:
public partial class User
{
public User()
{
this.dfcs = new HashSet<Dfc>();
this.fids = new HashSet<Fid>();
this.histroyDeliverRequests = new HashSet<Histroyrequest>();
this.histroyProposalRequests1 = new HashSet<Histroyrequest>();
}
public string Name { get; set; }
public string Role { get; set; }
public string Email { get; set; }
public string Group { get; set; }
public int Id { get; set; }
public short SoftwareVersion { get; set; }
public virtual ICollection<Dfc> dfcs { get; set; }
public virtual ICollection<Fid> fids { get; set; }
public virtual ICollection<Histroyrequest> histroyDeliverRequests { get; set; }
public virtual ICollection<Histroyrequest> histroyProposalRequests1 { get; set; }
public virtual Software Software { get; set; }
}

I am thinking you should omit the Id, when inserting into the User Table, as I would think that the Id would auto increment, when inserting a new record?

Related

EF Core 2 Stopping Circular Dependency on Many to Many Relationship

I am using the Sakila Sample Database from MySql on a MySql server. The Diagram looks as follows.
The important tables are the store, inventory and film tables. The is a many-to-many relationship between the tables and the linker table is the inventory table.
I scaffolded this Database in a new dotnetcore project using EFCore 2.
I am trying to get a list of stores and their list of films.
The Entities are defined as follows:
Store
public class Store
{
public Store()
{
Customer = new HashSet<Customer>();
Inventory = new HashSet<Inventory>();
Staff = new HashSet<Staff>();
}
public byte StoreId { get; set; }
public byte ManagerStaffId { get; set; }
public short AddressId { get; set; }
public DateTimeOffset LastUpdate { get; set; }
public Address Address { get; set; }
public Staff ManagerStaff { get; set; }
public ICollection<Customer> Customer { get; set; }
public ICollection<Inventory> Inventory { get; set; }
public ICollection<Staff> Staff { get; set; }
}
Inventory
public partial class Inventory
{
public Inventory()
{
Rental = new HashSet<Rental>();
}
public int InventoryId { get; set; }
public short FilmId { get; set; }
public byte StoreId { get; set; }
public DateTimeOffset LastUpdate { get; set; }
public Film Film { get; set; }
public Store Store { get; set; }
public ICollection<Rental> Rental { get; set; }
}
Film
public partial class Film
{
public Film()
{
FilmActor = new HashSet<FilmActor>();
FilmCategory = new HashSet<FilmCategory>();
Inventory = new HashSet<Inventory>();
}
public short FilmId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public short? ReleaseYear { get; set; }
public byte LanguageId { get; set; }
public byte? OriginalLanguageId { get; set; }
public byte RentalDuration { get; set; }
public decimal RentalRate { get; set; }
public short? Length { get; set; }
public decimal ReplacementCost { get; set; }
public string Rating { get; set; }
public string SpecialFeatures { get; set; }
public DateTimeOffset LastUpdate { get; set; }
public Language Language { get; set;
public Language OriginalLanguage { get; set; }
public ICollection<FilmActor> FilmActor { get; set; }
public ICollection<FilmCategory> FilmCategory { get; set; }
public ICollection<Inventory> Inventory { get; set; }
}
My context looks as follows:
modelBuilder.Entity<Inventory>(entity =>
{
entity.ToTable("inventory", "sakila");
entity.HasIndex(e => e.FilmId)
.HasName("idx_fk_film_id");
entity.HasIndex(e => new { e.StoreId, e.FilmId })
.HasName("idx_store_id_film_id");
And lastly the repo looks as follows:
public IEnumerable<Store> GetStores()
{
return _context.Store.
Include(a => a.Inventory).
ToList();
}
Problem:
When I call this method from a Controller to get the list of stores I don´t get any json response on Postman. Yet if I debug into the list that is returned from the Controller I find the list of stores.
The problem is that the list contains:
store->inventory->film->store->inventory->film->store... Etc. Creating a circular dependency that fills up the allowed Process memory of the request.
Possible Solutions:
I think it has to do with the fact that on the Context both the Foreign Keys are defined as HasIndex instead of HasKey
entity.HasIndex(e => new { e.StoreId, e.FilmId })
.HasName("idx_store_id_film_id");
When I define it as HasKey then I get an Error:
'The relationship from 'Rental.Inventory' to 'Inventory.Rental' with
foreign key properties {'InventoryId' : int} cannot target the primary
key {'StoreId' : byte, 'FilmId' : short} because it is not compatible.
Configure a principal key or a set of compatible foreign key
properties for this relationship.'
To answer #hamzas comment, I did find a solution to this problem. I used EFCore to build the entities and the DBContext through scaffolding (DB First). As a best practice you should be using Models (Dtos) to represent the Data for the client. EFCore is very helpful in giving us the flexibility to access this M to N relationship however we want. This gives us the flexibility to represent this Data to the client however we want.
Whatever your use case might be. You have to convert the M to N relationship into an 1 to N model.
Use Case #1: You want to show all the movies for a specific store.
Solution
Step #1: You create a StoreDto (Model)
public class StoreDto
{
int StoreId { get; set; }
ICollection<FilmDto> Films { get; set; }
= new List<FilmDto> ();
}
Step #2: Create a FilmDto
public class FilmDto
{
int FilmId { get; set; }
int StoreId { get; set; }
string FilmName { get; set; }
}
Step #3: You provide a Mapping with auto mapper
public class MappingProfiles : Profile
{
public MappingProfiles()
{
CreateMap<Store, StoreDto>();
CreateMap<Film, FilmDto>();
}
}
Step #4: Query the data correctly, Unfortunately I don´t have this example anymore to test this code, so here is where you´ll have to experiment a bit
public Store GetFilmsForStore(byte StoreId)
{
return _context.Store.
Include(a => a.Inventory).
ThenInclude(i => i.Film)
ToList();
}
On the "Include" part you want to only get the Inventory entries where StoreId == Inverntory.StoreId and then Include the Films Object from the resulting list.
I hope you get the jist of it. You want to break up your m to n relationships and make them seem like 1 to m for your clients.

AspNet EF referencing foreign key to field

Im having two models:
public class Customer
{
public int Id { get; set; }
public int Number { get; set; }
public int ParentNumber { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string Language { get; set; }
}
and
public class Batch
{
public int Id { get; set; }
public int Number { get; set; }
public string FileName { get; set; }
public string ArticleNumber { get; set; }
public string ArticleDescription { get; set; }
public int Weight { get; set; }
public DateTime ProductionDate { get; set; }
public DateTime DeliveryDate { get; set; }
public DateTime BestBeforeDate { get; set; }
public DateTime? ApprovedDateTime { get; set; }
public int CustomerId { get; set; }
public virtual Customer Customer { get; set; }
}
One batch can have a customer attached to it. But since we're importing the data from another system we decided not to take over their id's.
Right now the foreign key says try to find a customer by the property Customer.Id
I'm trying to achieve to get the foreign key point to Customer.Number from Batch.Customer(Id)
How would i succeed in this?
I've tried by defining the Customer.Number to be a Key with the Key attribute.. but this made the primary key go from Id to Number which is not what i wanted...
What are you asking was impossible in EF prior to EF Core. Fortunately in EF Core it can be done by using Alternate Keys feature. But please note that in order to be able to use it, your Cusomer.Number field should be unique.
The solution requires Fluent API configuration.
Start by defining Customer.Number as alternate key:
modelBuilder.Entity<Customer>()
.HasAlternateKey(e => e.Number);
Then set up the relationship as follows:
modelBuilder.Entity<Batch>()
.HasOne(e => e.Customer)
.WithMany()
.HasForeignKey(e => e.CustomerId)
.HasPrincipalKey(e => e.Number);
The last two lines will do what you are seeking for.
As a side note, it would be better to name the property (and column) CustomerNumber in order to avoid confusion of what the value is in it.

How to limit data in a mobile API using EF and WebAPI/JSON

I am writing a PhoneGap/Web/JS mobile application that uses the WebAPI and Entity Framework in the backend.
I have a class called Thing which references the User table 4 times (ChangedByUserId, CreatedByUserId etc. The User table is really large (30 user-related fields)
I want to pass as little data over each call as possible, but I need the User's Name for each of these UserID foreign keys. (this is the only information from the user record I need).
When I use the object graph in EF it returns the FULL user record for each foreign key, so a single Thing object becomes massively bloated. I don't want to make multiple calls to get the Thing POCO object and then the User's name by UserID.
What I really want to do is a sort of flattened DTO object which is just the Thing class below but with a string for each user name, e.g. CreatedByUserName, ChangedByUserName etc. Then I would return this DTO as my hydrated POCO object and the data would be small.
So my question is: How do I do this using Entity Framework? (limit related record's return data?)
public partial class Thing
{
public int ThingId { get; set; }
public int FromUserId { get; set; }
public int ToUserId { get; set; }
public string ThingText { get; set; }
public int StatusId { get; set; }
public int ChangedByUserId { get; set; }
public int CreatedByUserId { get; set; }
public virtual User FromUser { get; set; }
public virtual User ToUser { get; set; }
public virtual User CreatedByUser { get; set; }
public virtual User ChangedByUser { get; set; }
}
As you said, you need to flatten Thing
public class FlatThing
{
public int ThingId { get; set; }
public int FromUserId { get; set; }
public int ToUserId { get; set; }
public string ThingText { get; set; }
public int StatusId { get; set; }
public int ChangedByUserId { get; set; }
public int CreatedByUserId { get; set; }
public string FromUserName { get; set; }
public string ToUserName{ get; set; }
}
// assume you have your things
var flatThings = new List<FlatThings>;
foreach (Thing t in things)
flatThings.Add(new FlatThing{ ThingId = t.ThingId, FromUserId = t.FromUserId,
FromUserName = t.FromUser.Name .....});
return flatThings;

Creating BiDirectional One - One relationship in Entity Framework 4.1 Code First

I want to created Bi-Directional One-One relationship between two entities using EF Code First. I have trouble with the following code. What do you think I should do?
public class User
{
public string ID { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public int ProfileID { get; set; }
public Profile Profile { get; set; }
}
public class Profile
{
public int UserID { get; set; }
public User User { get; set; }
public int ProfileID { get; set; }
public string ProfileName { get; set; }
public DateTime CreateDate { get; set; }
public DateTime LastUpdateDate { get; set; }
}
I want to have both Navigation property and Foreign Key in both the entities.
This gives me error. What can do I in Fluent Mapping API to make this work?
Use this:
public class User
{
public string ID { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public Profile Profile { get; set; }
}
public class Profile
{
[Key, ForeignKey("User")]
public int ProfileID { get; set; }
public string ProfileName { get; set; }
public DateTime CreateDate { get; set; }
public DateTime LastUpdateDate { get; set; }
public User User { get; set; }
}
That is the only valid way to build one-to-one relation in EF - PK of the dependent entity must be also FK to principal entity. There is nothing like bidirectional one-to-one relation in EF because it cannot work in EF.
The way how people sometimes overcome this are two one-to-many relations where principal doesn't have navigation collection for dependent entities + manually defined unique keys in the database. That require manual mapping:
public class User
{
public string ID { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
// one side MUST be nullable otherwise you have bidirectional constraint where each
// entity demands other side to be inserted first = not possible
public int? ProfileId { get; set; }
public Profile Profile { get; set; }
}
public class Profile
{
public int ProfileID { get; set; }
public string ProfileName { get; set; }
public DateTime CreateDate { get; set; }
public DateTime LastUpdateDate { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
And in mapping you will define:
modelBuilder.Entity<User>
.HasOptional(u => u.Profile)
.WithMany()
.HasForeignKey(u => u.ProfileId);
modelBuilder.Entity<Profile>
.HasRequired(u => u.User)
.WithMany()
.HasForeignKey(u => u.UserId);
Now you must define Unique keys in the database - if you are using code first use custom database initializer. Be aware that still bidirectional one-to-one is wrong concept because both sides demand unique FK where NULL is still included in unique values so once you insert User before Profile there mustn't be any other User without Profile. That probably leads to serializable transaction.

Help Configuring Associations in Castle Active Record in case of association table

I have tables like
Users (UserId,Username,Password,CreatedOn,CreatedBy)
Roles (RoleId,RoleName,Description,CreatedOn,CreatedBy)
UserRoleMap(UserRoleMapId,UserId,RoleId,CreatedOn,CreatedBy)
These are my entities:
[ActiveRecord(Table="Users")]
public class User:ActiveRecordBase<User>
{
[PrimaryKey(Generator = PrimaryKeyType.Identity, Column = "RoleId")]
public virtual int UserId { get; set; }
[Property(Column="Username")]
public virtual string Username { get; set; }
[Property(Column = "Password")]
public virtual string Password { get; set; }
[Property(Column="CreatedBy")]
public virtual string CreatedBy { get; set; }
[Property(Column="CreatedOn")]
public virtual DateTime CreatedOn { get; set; }
[HasAndBelongsToMany(Table="UserRoleMap",ColumnKey="UserId")]
public IList<Role> Roles { get; set; }
}
[ActiveRecord(Table = "Roles")]
public class Role : ActiveRecordBase<User>
{
[PrimaryKey(Generator = PrimaryKeyType.Identity, Column = "RoleId")]
public virtual int RoleId { get; set; }
[Property(Column = "RoleName")]
public virtual string RoleName { get; set; }
[Property(Column = "Description")]
public virtual string Description { get; set; }
[Property(Column = "CreatedBy")]
public virtual string CreatedBy { get; set; }
[Property(Column = "CreatedOn")]
public virtual DateTime CreatedOn { get; set; }
[HasAndBelongsToMany(Table = "UserRoleMap", ColumnKey = "RoleId")]
public IList<User> Users { get; set; }
}
[ActiveRecord(Table="UserRoleMap")]
public class UserRoleMap:ActiveRecordBase<UserRoleMap>
{
[PrimaryKey(Generator = PrimaryKeyType.Identity, Column = "UserRoleMapId")]
public virtual int UserRoleMapId { get; set; }
[BelongsTo(Column="UserId",Table="Users")]
public virtual User UserId { get; set; }
[BelongsTo(Column = "RoleId", Table = "Roles")]
public virtual Role RoleId { get; set; }
}
I keep getting this error:
ActiveRecordSample.Tests.FrameworkInitializationTest.CanInitializaFramework : Castle.ActiveRecord.Framework.ActiveRecordException : Property UserId references table "Users", which does not have a corresponding [JoinedTable] on the class.
Wherever the column name matches the property name, you don't need to set Column="..."
User.UserId is mapped to column "RoleId", it should be "UserId" (or as I said in the above point, just don't define it)
Make sure to understand the pros and cons of each PK generator.
When using HasAndBelongsToMany you don't want a separate relationship class (in your case UserRoleMap).
IIRC you also need to define the other FK in HasAndBelongsToMany with ColumnRef.