How to use AutoMapper with Entity Framework Database First approach - c#

I am working on MVC 5, Entity Framework with Db First Approach. Whenever i use
public class Customer
{
[Required]
public virtual string CustomerID { get; set; }
[Required]
[StringLength(15)]
public virtual string CompanyName { get; set; }
public virtual string Address { get; set; }
public virtual string City { get; set; }
public virtual string PostalCode { get; set; }
[Country(AllowCountry="USA")]
public virtual string Country { get; set; }
[Phone]
public virtual string Phone { get; set; }
}
for Validation in Entity Framework generated class and if i update my .edmx file i lost all code that i was written. Someone suggest me use Auto-mapper. I try to find some basic example but i didn't get. Guide me. How to start and where from? I am new in MVC, Entity Framework.

There is another approach to retain the validation attribute code even if you update the model.
In the Models folder, add a class named Metadata.cs (class that contain all of the validation attributes).
using System;
using System.ComponentModel.DataAnnotations;
namespace YourProjectName.Models
{
public class CustomerMetadata
{
[Required]
public virtual int CustomerId { get; set; }
[Required]
[StringLength(15)]
public virtual string CompanyName { get; set; }
}
}
Next, you must associate the model classes with the metadata classes.For that In the Models folder, add a class named PartialClasses.cs.
using System;
using System.ComponentModel.DataAnnotations;
namespace YourProjectName.Models
{
[MetadataType(typeof(CustomerMetadata))]
public partial class Customer
{
}
}
Source

Related

How you can create one-to-one relationship from different assembly in EF Core 2.0

I want using simple table splitting in my project for learning about that but how you can make that in different assembly?
I have two class library that named as MyApp.Core and MyApp.CommerceService
In .Core project I have User entity:
public partial class User
{
public long UserId { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public Customer Customer { get; set; }
}
In .CommerceService I have Customer entity:
public partial class Customer
{
private ICollection<Address> _addresses;
public Customer()
{
this.CustomerGuid = Guid.NewGuid();
}
public long UserId { get; set; }
public User User { get; set; }
public Guid CustomerGuid { get; set; }
public int VendorId { get; set; }
public virtual Address BillingAddress { get; set; }
public virtual Address ShippingAddress { get; set; }
public virtual ICollection<Address> Addresses
{
get { return _addresses ?? (_addresses = new List<Address>()); }
protected set { _addresses = value; }
}
}
That's fine if Customer entity placed in .Core project. Now I have problem with adding assembly references because that makes cycle.
I'm student please give me a tip for this. Thank you.
Your issue is with a circular dependency of your projects the simplest way to get around this is to extract all of your entities to another project I would create a new project MyApp.Entities or MyApp.DataAccess.
Place all of your entities in this project and you can then reference this project from both core and CommerceService. I would also suggest moving any EF related files such as context here as well.

MVC 5 Code First adding new database table with UserId

So right now my IdentityModels.cs looks like this:
using System;
using System.Data.Entity;
using System.Security.Claims;
using System.Security.Policy;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Leepio.Models
{
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string City { get; set; }
//company
[Display(Name = "Virkshomedsnavn")]
public string CompanyName { get; set; }
public string ZipCode { get; set; }
//company
public int NrEmployees { get; set; }
//company
public string WorkField { get; set; }
public string Language { get; set; }
//Student
public string University { get; set; }
public string StudyProgramme { get; set; }
public int Semester { get; set; }
public string GraduationDate { get; set; }
//
[AllowHtml]
public string Description { get; set; }
//Student
public string Skills { get; set; }
public string Website { get; set; }
public string Address { get; set; }
//Student
[DataType("date")]
public DateTime DateOfBirth { get; set; }
public virtual ICollection<Blog> Blogs { get; set; }
public virtual ICollection<Application> Applications { get; set; }
public virtual ICollection<Project> Project { get; set; }
public virtual IList<Experience> Experience { get; set; }
public virtual ICollection<Skill> Skill { get; set; }
public virtual IList<Education> Education { get; set; }
public virtual IEnumerable<Experience> ExperienceOrdered { get { return Experience.OrderByDescending(e => e.EndYear); } }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
public System.Data.Entity.DbSet<Leepio.Models.Project> Projects { get; set; }
public System.Data.Entity.DbSet<Leepio.Models.NewsletterMails> NewsletterMails { get; set; }
public System.Data.Entity.DbSet<Skill> Skill { get; set; }
public System.Data.Entity.DbSet<Leepio.Models.Application> Applications { get; set; }
public System.Data.Entity.DbSet<Leepio.Models.Contract> Contracts { get; set; }
public System.Data.Entity.DbSet<Leepio.Models.Experience> Experience { get; set; }
public System.Data.Entity.DbSet<Leepio.Models.Blog> Blogs { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Education> Educations { get; set; }
}
}
What I want to do is, through code (migrations), add a new table as an extensions to the user table (AspNetUsers) through code as to when I register a new user with data taken from facebook, the data that I don't need for the main Users Table can go to the second one, lets say call it "FBData" with the appropriate userId.
To put it in perspective:
Register user would add userID, FirstName, LastName, Email to Users table and at the same time add ID and Locale, Gender in the FBData table.
Microsoft Identity uses AspNetUserClaims to store all additional data you specified in your ApplicationUser model class. When you use external Authentication Provider such as Facebook, Google etc. a new entry is created in AspNetUserLogins table to store the ProviderKey. This key is used when user is logging in to your application for the second time.
For my understanding your plan to create a FBData table is not necessarily good. How about you add Google Authentication after? Will you create a GData table?
The best option would be in your AccountController in ExternalLoginCallback (function triggered when the user is redirected back from your external authentication provider to your page) map what you received from facebook to your ApplicationUser and maybe redirect the the user to the registration form with pre-populated fields to finish the registration cycle. All the trash data you can store if you like in a separate table AspNetUserClaims_External but you have to model it first.
Check:
https://github.com/IdentityServer/IdentityServer4.Samples/tree/dev/Quickstarts/4_ImplicitFlowAuthenticationWithExternal
There are a few things you need to do. First you can create a FbData class with the properties you need in that table. Then add the properties you need to the ApplicationUser Class. You need the foreign key for the FbData table
public int FbDataId { get; set; }
and you also need to add the virtual property for the table:
public virtual ICollection<FbData> FbDatas { get; set; }
Last in your IdentityContext add you DbSet for your table:
public DbSet<FbData> FbData { get; set; }
Run the application on a clean db to see your changes reflected..
You can also override the OnModelCreating class in your IdentityContext to make any modifications to the Generated Identity Tables.

Why database first classes differ from my code first classes

I am migrating to SQL Server from MySql and re-writing a website in C# (I was/am a vb.net guy) using code-first.
I wrote the following class
namespace DomainClasses.GeographyDb
{
public class PostalCode
{
[Key]
public int PostalCodeId { get; set; }
[Required]
[DataType(DataType.PostalCode)]
public string PostCode { get; set; }
[Required, ForeignKey("City")]
public int CityId { get; set; }
[Required, ForeignKey("TimeZone")]
public int TimeZoneId { get; set; }
[Required, MaxLength(30)]
public string AreaRegionPhonePrefixCode { get; set; }
[MaxLength(10)]
public string TaxRegionCode { get; set; }
public virtual City City { get; set; }
public virtual TimeZone TimeZone { get; set; }
}
I wanted to see what Entity Framework would write if it were creating the class so I created a test project and using code first from database option I imported an existing database of exact same fields as I wrote the custom classes for.
Here is what it produced;
namespace CodeFirstCreationTest
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class postalcode
{
public long PostalCodeId { get; set; }
[Required]
[StringLength(10)]
public string PostCode { get; set; }
public long CityId { get; set; }
public long TimeZoneId { get; set; }
[Required]
[StringLength(10)]
public string AreaRegionPhonePrefixCode { get; set; }
[StringLength(10)]
public string TaxRegionCode { get; set; }
public virtual city city { get; set; }
public virtual timezone timezone { get; set; }
}
}
I have a number of questions as to the differences;
Why did Entity Framework put all the using statements INSIDE the namespace declaration? I thought they were always to be outside and before the code
StringLength is a data validation annotation. Why did Entity Framework put that attribute on the property, isn't it for UI validation? And now that I think of it I always put Required attribute on classes, is that a data validation annotation as well and not a database annotation?
It created a database class using fluent API and modelbuilder. Is it better to annotate the class properties or do it using the modelBuilder in the OnModelCreating method?
Why did Entity Framework make this class partial and apparently all the classes it generates as partial?
Using statements are sometimes generated inside the actual namespace declaration. Usually there is no difference. Only in some cases is it a bit different. Please see this answer for more info, since it is explained better than I would be able to: https://stackoverflow.com/a/151560/1757695
StringLength and Required are both database annotations and the according operations are executed right before saving the data in the database. For example if you were trying to save a User and the user had a UserName property decorated with Required data annotation, you would get an error only when you called SaveChanges method and not when you assigned the value to the property.
I believe it is personal preference. I prefer data annotations and as little as possible fluent API. There are still some things that you can't do with data annotations but can do with fluent API.

How to avoid creating a parent when adding a child record in Entity Framework?

There are 2 tables in database, one is [PARENTS] and the other one is [CHILDREN] - having a ParentId as foreign key.
so the relationship between PARENTS and CHILDREN is one-many.
The problem was when I was trying to creating a new CHILDREN record, it would be creating a new PARENT too.
How to solve it ? Thank you
public void Add(Model.Pages.PageGroup entity)
{
using (var ctx = new SmartDbContext())
{
var dbEntity = entity.ToEntity();
ctx.PageGroups.Add(dbEntity);
ctx.SaveChanges();
}
}
namespace SmartECM.Repository.EF
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class PageGroup
{
public PageGroup()
{
Pages = new HashSet<Page>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid GroupId { get; set; }
[Required]
[StringLength(100)]
public string GroupName { get; set; }
public Guid ProjectId { get; set; }
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Computed)]
public DateTime? DateAdded { get; set; }
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Computed)]
public DateTime? DateUpdated { get; set; }
public virtual Project Project { get; set; }
public virtual ICollection<Page> Pages { get; set; }
}
}
namespace SmartECM.Repository.EF
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class Project
{
public Project()
{
PageGroups = new HashSet<PageGroup>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ProjectId { get; set; }
[Required]
[StringLength(100)]
public string ProjectName { get; set; }
public string ProjectDescription { get; set; }
public Guid? Owner { get; set; }
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Computed)]
public DateTime? DateAdded { get; set; }
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Computed)]
public DateTime? DateUpdated { get; set; }
public virtual ICollection<PageGroup> PageGroups { get; set; }
}
}
Thanks everyone!!!
I've got the correct answer from this link Entity Framework - Duplicate parent(one) when create new child(many)
It should attach the parent to let the EF can detect it, I guess.
Based on what you've posted so far, I think that your problem is coming from where you are setting the values on the entity in question (i.e. before you call the Add() method). What I think that you're doing is that you're setting the Project navigation property on your PageGroup entity, and then trying to save it like that.
The problem with doing it that way is that when you add the PageGroup entity to the collection EF sees that the ProjectId field is null and assume that the data found in the Project navigation property is a brand new Project that is not currently in the system. It will then go right ahead and create that "new" Project in the database in order to add your PageGroup entity to its collection.
The solution then is to just populate the ProjectId field with the ID of the Project that you're trying to associate it to, and not assign anything to the navigation property. That way EF will know which Project you're trying to assign your entity to.

Modify Add Method in Entity Framework

I'm new to entity framework technology and I just generated 3 classes from my tables:
Project
Resource
Employees
I wanted to set a condition that the resource can't be used by two projects and I want that in my project's Add method how can I modify it, is it even possible to modify it?
public partial class Project
{
public int Id { get; set; }
public string Name { get; set; }
public Nullable<int> Resource { get; set; }
public Nullable<int> Manager { get; set; }
public Nullable<System.DateTime> StartDate { get; set; }
public Nullable<System.DateTime> Deadline { get; set; }
public Nullable<System.DateTime> EndDate { get; set; }
public virtual Emploee Emploee { get; set; }
public virtual Resource Resource1 { get; set; }
}
You can modify it but it will override when you generate again. Add partial class and put your method there.
//Your partial class
public partial class Project
{
public string DoCustomWork()
{
}
}
Since you are using data first, if you want the resource to be unique to a single project, then create a unique constraint on the resource FK in the project table.

Categories

Resources