i need to import a new table in Nop database, and i need to create the data access layer like others tables.
The table has a primary key column which name is SignatureId and my client don't want to change this name.
So i can't inherit from BaseEntity abstract class because it implies that the primary Key table must call "Id".
My question is :
Is it a problem to create a new Domain entity class who is not inherit from BaseEntity ? Like :
public class Signature
{
public int SignatureId { get; set; }
public string Hash{ get; set; }
public.....
}
Maybe it must implies so problem during entity manipulations ? Can you advice me about that ?
A quick solution would be using both id and signatureId. So you will be inline with your client and nopcommerce.
Repository pattern is used in nopcommerce to store data using base entity. So creating an entity without inheriting from base would break the design.
I am late but the answer is yes you can, even if you inherit from it. You just need to ignore it in the mapping like below;
public class Signature : BaseEntity
{
public int SignatureId { get; set; }
public string Hash{ get; set; }
public.....
}
In the mapping i.e Nop.Data -> Mapping
public class SignatureMap : NopEntityTypeConfiguration<Signature>
{
this.Ignore(c => c.Id);
this.HasKey(c => c.SignatureId);
}
Related
I use ASP.NET Core with Identity and want to extend default Db context. If I want to add not linked table I just add a new class:
public partial class Table1
{
public int Id { get; set; }
public string Txt { get; set; }
}
and extend my ApplicationDbContext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public virtual DbSet<Table1> Table1 { get; set; }
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<Table1>(entity =>
{
entity.ToTable("Table_1");
entity.Property(e => e.Id).HasColumnName("ID");
entity.Property(e => e.Txt)
.IsRequired()
.HasMaxLength(50);
});
}
}
then create a migration and update db. It works. But if I want to add a new table, which linked to table from IdentityDbContext:
public partial class Users
{
public int Id { get; set; }
public string UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual AspNetUser User { get; set; }
}
of course, AspNetUser class does not exist (it's created by IdentityDbContext, as I understand). How to do it correctly?
The class is most likely named ApplicationUser (the default). The table that represents this entity is dbo.AspNetUsers, but that is set by Identity, and has nothing to do with the class name.
FWIW, though, it's a bad idea to create a Users entity, for a number of reasons:
There will undoubtedly be confusion between Users and ApplicationUser, as well as the database tables dbo.Users and dbo.AspNetUsers.
In general, you should name your entities in singular tense, i.e. User, not Users. There's a whole host of reasons for this convention, but suffice to say, it just makes your code better and more readable to stick to singular tense for singular things and plural tense for plural things. For example, a property of type ICollection<User> would be named Users, since it's composed of many User instances.
What you're doing is completely unnecessary. The whole reason for Identity's existence is that Membership (the previous authentication and authorization framework employed by ASP.NET) did not allow you to extend the types involved. Identity changes all this and is 100% extensible in every way. You have full access to all entities involved in the the framework and you can add to them and derive from them. If you want to add additional properties for "users" in your system, just add them to the ApplicationUser class directly.
Basically, I want to have a user that can create their own stories.
I have these classes:
public class ApplicationUser : IdentityUser
{
public string DisplayedName { get; set; }
}
public class Story
{
public int Id { get; set; }
public string Content { get; set; }
}
They are managed on a different context and so as their migration. Something like this.
public class MyDbContext : DbContext
{
public DbSet<Story> Stories { get; set; }
}
public class IdentityContext : IdentityDbContext<ApplicationUser>
{
}
When I try to add a migration then update them individually, it works fine but when I try to add a collection of stories in my application user.
public class ApplicationUser : IdentityUser
{
public string DisplayedName { get; set; }
public virtual ICollection<Story> Stories { get; set; }
}
public class Story
{
public int Id { get; set; }
public string Content { get; set; }
public string WrittenById { get; set; }
public virtual ApplicationUser WrittenBy { get; set; }
}
public class StoryMap : EntityTypeConfiguration<Story>
{
public StoryMap()
{
HasOptional(s => s.WrittenBy)
.WithMany(s => s.Stories)
.HasForeignKey(s => s.WrittenById)
.WillCascadeOnDelete(false);
}
}
Then do a migration on my Story entity using the contenxt of MyDbContext it fails saying.
Data.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType.
Data.IdentityUserRole: : EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType.
IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is based on type 'IdentityUserLogin' that has no keys defined.
IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on type 'IdentityUserRole' that has no keys defined.
But when I try the other way around in which I'll do a migration using the IdentityContext it would create a new table of Story
For now, what works is merging my contexts. Something like.
public class MyDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<Story> Stories { get; set; }
}
But there must be a way of managing them separately, right? Or am I doing it all wrong?
You can't reference entities from one context in another, or that context will attempt to manage those entities as well, resulting in errors about tables already existing. You have two options:
If you don't actually need two separate contexts (i.e., they're both Code First and you're fine with everything being in one database), then the best and easiest solution is to just merge them as you've done. There's no benefit to having multiple contexts, and as you've seen, there's plenty of detriment. The only good reason to ever use multiple contexts is if you're dealing with additional existing databases.
Create a simple column to store the related id (not a foreign key). You lose the optimization of having a true foreign key and the ability to lazy load, but you can still at least somewhat relate things this way. Essentially, you just set this property with the id of the related object in the other context. Then, when you need to retrieve that object, you just issue a query with that other context, utilizing that id. In other words, you just manually fetch the objects.
That's your only options, unfortunately.
I've been trying to create model in EF 4.1 to represent a database schema with a single table and column holding foreign keys from two other tables, but have had little luck with both annotations and the fluent API. A sample model is shown here:
public class User
{
...
public virtual ExtendedAttribute ExtendedAttributes { get; set; }
}
public class Account
{
...
public virtual ExtendedAttribute ExtendedAttributes { get; set; }
}
public class ExtendedAttribute
{
public Guid Id {get; set;}
public Guid ItemId {get; set;} // both Account.Id and User.Id stored here
public string Value { get; set; }
}
Currently the configuration for these entities looks something like this for both User and Account modelBuilders:
this.HasOptional(u => u.ExtendedAttributes).WithRequired();
Any thoughts on how to do achieve? Many thanks.
It is even not possible with the database itself and EF will not put any abstraction for that. You must have separate column and navigation property for each entity.
I've seen somewhere how to do this before on a blog but I forgot where or how. Lets say I have a domain in a class library. I'd like to data annotate the properties of this domain as my viewmodel in the web project.
How do I accomplish this?
For example. This domain is in my class library:
public class Person {
public int Id {get; set;}
public string FirstName {get; set;}
}
In my web project, there is this:
//Do i need to set some attribute here?
public class CreatePersonViewModel{
[Required()]
[DisplayName("First Name")]
public string FirstName {get; set;}
}
This code can be mapped to Person without a tool. Probably partial or something.
The whole idea of using a view model is to decouple it from your domain model and to have something which is adapted to the needs of the view. The view model should be declared in the web project and contain all the necessary properties and formatting attributes that this particular view might require. The domain model shouldn't be polluted with any view specific data annotations. So if your model looks like this:
public class Person {
public int Id { get; set; }
public string FirstName { get; set; }
}
You could have the following view model:
public class CreatePersonViewModel {
[Required]
[DisplayName("First Name")]
public string FirstName { get; set; }
}
and then have the controller fetch the model from some repository, map it to the view model (AutoMapper can help you here) and pass the view model to the view.
Do you mean annotate your Domain objects or your view model objects?
Using the System.ComponentModel.DataAnnotations validation attributes (and deriving any of your own from ValidationAttribute, you can validate values bound to the properties of your viewmodel at the point of model binding.
Scott Guthrie has a detailed blog post about Model validation with data annotation validation attributes.
EDIT: you say in a comment to another poster that your types already exist. You can add the MetadataTypeAttribute to the existing type to indicate another type that holds the validation logic to be applied to the properties of your existing type.
You can create a 'buddy' class for your data annotation attributes
[MetadataType(typeof(ResourceMetadata))]
public partial class Resource
{
public object Value { get; set; }
}
public class ResourceMetadata
{
// The metadata class can define hints
[UIHint("ResourceValue")]
public object Value { get; set; }
}
Are you talking about this type of thing?:
using System.ComponentModel.DataAnnotations;
public MyClass
{
[DisplayName("Street Address")]
public string StreetAddress { get; set; }
}
EDIT:
If you need to add Data Annotations to generated class like an Entity do this:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
namespace Something
{
[MetadataType(typeof(MetaMyClass))]
public partial class MyClass
{
//You can just leave this empty if you have nothing additional to add to the class
}
public class MetaMyClass
{
[DisplayName("Street Address")]
public string StreetAddress { get; set; }
}
}
I am using EF4 code first and want to generate a composite key which is made of a class property and foreign key. I have two classes: Order and Company. The Order class holds a reference but this will not necessarily be unique between companies. So I intend to use a composite key made up of Reference and Company.CompanyId.
I have tried using the following to set it but I get an error message "Key expression is not valid".
modelBuilder.Entity<Order>().HasKey(o => new { o.Reference, o.Company.CompanyId });
I have also tried
modelBuilder.Entity<Order>().HasKey(o => new { o.Reference, o.Company });
and this fails.
these are my classes:
public class Order
{
public string Reference { get; set; }
public Company Company { get; set; }
}
public class Company
{
public int CompanyId { get; set; }
public virtual ICollection Orders { get; set; }
}
Any help would be greatly appreciated.
As Antony Highsky mentioned, you can only use scalar properties in the key.
So, you will need to add a foreign key (scalar property) to the Order class and associate it with the navigation property Company as shown below:
public class Order
{
public string Reference { get; set; }
public int CompanyId { get; set; }
[RelatedTo(ForeignKey = "CompanyId")]
public Company Company { get; set; }
}
And then create the composite key using the model builder:
modelBuilder.Entity<Order>().HasKey(o => new { o.Reference, o.CompanyId });
Note that data annotations (RelatedTo attribute) were introduced with the Entity Framework CTP 3. For another option that only uses data annotations instead of HasKey method, see this post:
http://www.luisrocha.net/2010/11/creating-composite-keys-using-code.html
One thing that doesn't look quite right is your use of the non-generic version of ICollection. Try this:
public virtual ICollection<Order> Orders { get; set; }
Did you try this?
modelBuilder.Entity().HasKey(o =>o.Reference );
modelBuilder.Entity().HasKey(o =>o.CompanyId );
According to this source, only scalar properties are allowed in the key. Navigation properties are not.