Code First update fields without required field - entity-framework-6

this is my entity:
public partial class Student
{
public string Code { get; set; }
public int Year { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
}
Config:
HasKey(e => new { e.Code, e.Year});
Property(b => b.Code).HasColumnName("CODE").IsUnicode(false).HasMaxLength(20).IsRequired();
Property(b => b.Year).HasColumnName("YEAR").IsRequired();
Property(b => b.Name).HasColumnName("NAME").IsUnicode(false).HasMaxLength(50);
Property(b => b.Gender).HasColumnName("GENDER").IsUnicode(false).HasMaxLength(2).IsRequired();
The gender field also has the required option.
In my update I only want to update the name field:
var student = new Student
{
Code = "WRK",
Year = 2018,
Name = "Test Name"
};
_context.Student.Attach(student);
_context.Entry(student).Property(x => x.Name).IsModified = true;
_context.SaveChanges();
On SaveChanges it gives a DbEntityValidationException, saying the gender field is required. Although I don't want to update it, but keep the existing value from the database.
Is there a proper solution without first querying the database to get the existing value for that gender field?
Thanks.

I use solution like this:
Public Overrides Function SaveChanges() As Integer
For Each changedEntity In Me.ChangeTracker.Entries
Select Case changedEntity.State
Case EntityState.Modified
Select Case If(changedEntity.Entity.GetType.Namespace = "System.Data.Entity.DynamicProxies", changedEntity.Entity.GetType.BaseType, changedEntity.Entity.GetType)
Case GetType(Student)
changedEntity.Property("Gender").IsModified = False
End Select
Next
Return MyBase.SaveChanges()
End Function

Related

A table has two links to another table. How does .Include specify one of those links?

tblWorkOrder has two links to tblUser through tblWorkOrder.EnteredBy and tblWorkorder.ClosedBy. The code below selects the ClosedBy link. How do I specify the OpenedBy link?
public IEnumerable<SelectListItem> GetEnteredBy()
{
using (var context = new FacilityEntities())
{
List<SelectListItem> user = context.tblWorkOrder.AsNoTracking().Include("tblUser")
.GroupBy(x => new { x.tblUser.LastName, x.tblUser.FirstName, x.tblUser.UserID })
.Select(x =>
new SelectListItem
{
Value = x.Key.UserID,
Text = string.Concat(x.Key.FirstName, " ", x.Key.LastName)
}).ToList();
var usertip = new SelectListItem()
{
Value = null,
Text = "Select"
};
user.Insert(0, usertip);
return new SelectList(user, "Value", "Text");
}
}
You need to define the relationship in your Entity, use ForeignKey attribute to explicitly define which foreign key is associated to which navigation property.
public class tblWorkOrder
{
public long? CloseById { get; set; } // ForeignKey
[Foreignkey("CloseById")] // CloseBy navigation property is associated to CloseById
public tblUser CloseBy{ get; set; } // assuming tblUser is the name of your entity
public long? EnteredById { get; set; }
[ForeignKey("EnteredById")]
public tblUser EnteredBy { get; set; }
...
}
Once you define your navigation property correctly, you can simply include them in the query:
context.tblWorkOrder.AsNoTracking().Include(r => r.CloseBy).Include(r => r.EnteredBy)
...

.NET Core identity user id comes differently from database

I am trying to get current user's id with identity in .NET Core. Managed to create new user and login with it but whenever logging in with same user identity returns different guid.
I have a product entity which stores userId as foreign key. Whenever I try to add new product it throws error because given userId is not in user table.
But I register a new user and go add new product immediately it works. Lists products. However, logout and login again with same user, products are not listed. When I debug it saw that the _userManager.GetUserId(User) returning a different value.
Why could it be happened?
How can I fix this?
UPDATE
My User Creation Code
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: false);
return RedirectToAction(nameof(HomeController.Index), "Home");
}
My User Login Code
var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
return RedirectToLocal(returnUrl);
}
Here is My ApplicationUser Model Class
public class ApplicationUser : IdentityUser
{
[Key]
[Column("TABLEID")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public override string Id { get; set; }
[Required]
[Column("AD")]
public string Name { get; set; }
[Required]
[Column("SOYAD")]
public string Surname { get; set; }
[Required]
[Column("AKTIF")]
public bool IsActive { get; set; }
[Required]
[Column("SIL")]
public bool IsDeleted { get; set; }
[Required]
[Column("KAYITTARIHI")]
public DateTime RecordDate { get; set; }
public List<Vehicle> Vehicles { get; set; }
public List<VehicleImage> VehicleImages { get; set; }
public List<TransportAdvertise> TansportAdvertises { get; set; }
public List<TransportRequest> TransportRequests { get; set; }
}
Here is My DbContext
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
public DbSet<Vehicle> Vehicles { get; set; }
public DbSet<VehicleImage> VehicleImages { get; set; }
public DbSet<TransportAdvertise> TransportAdvertises { get; set; }
public DbSet<TransportRequest> TransportRequests { get; set; }
public DbSet<TransportRoute> TransportRoutes { get; set; }
public DbSet<City> Cities { 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);
// Identity built-in models.
builder.Entity<IdentityUser>().ToTable("TBLKULLANICI");
builder.Entity<IdentityRole>().ToTable("TBLROL");
builder.Entity<IdentityUserRole<string>>().ToTable("TBLKULLANICIROL");
builder.Entity<IdentityRoleClaim<string>>().ToTable("TBLROLECLAIM");
builder.Entity<IdentityUserClaim<string>>().ToTable("TBLUSERCLAIM");
builder.Entity<IdentityUserLogin<string>>().ToTable("TBLUSERLOGIN");
builder.Entity<IdentityUserToken<string>>().ToTable("TBLUSERTOKEN");
// Custom models.
builder.Entity<Vehicle>().ToTable("TBLARAC");
builder.Entity<VehicleImage>().ToTable("TBLARACRESIM");
builder.Entity<TransportAdvertise>().ToTable("TBLNAKLIYEILAN");
builder.Entity<TransportRequest>().ToTable("TBLNAKLIYEISTEK");
builder.Entity<TransportRoute>().ToTable("TBLROTA");
builder.Entity<City>().ToTable("TBLSEHIR");
// FK mappings..
builder.Entity<Vehicle>()
.HasOne(v => v.User)
.WithMany(u => u.Vehicles)
.HasForeignKey(v => v.UserId)
.HasConstraintName("FK_VEHICLE_USER");
// Vehicle image model fks.
builder.Entity<VehicleImage>()
.HasOne(vi => vi.Vehicle)
.WithMany(v => v.Images)
.HasForeignKey(vi => vi.VehicleId)
.HasConstraintName("FK_VEHICLE_IMAGE_VEHICLE");
builder.Entity<VehicleImage>()
.HasOne(vi => vi.User)
.WithMany(u => u.VehicleImages)
.HasForeignKey(vi => vi.UserId)
.HasConstraintName("FK_VEHICLE_IMAGE_USER");
// TransportAdvertise model fks.
builder.Entity<TransportAdvertise>()
.HasOne(ta => ta.User)
.WithMany(u => u.TansportAdvertises)
.HasForeignKey(ta => ta.UserId)
.HasConstraintName("FK_TRANSPORT_ADS_USER");
builder.Entity<TransportAdvertise>()
.HasOne(ta => ta.Vehicle)
.WithMany(v => v.TransportAdvertises)
.HasForeignKey(ta => ta.VehicleId)
.HasConstraintName("FK_TRANSPORT_ADS_VEHICLE");
// TransportRequest model fks.
builder.Entity<TransportRequest>()
.HasOne(tr => tr.User)
.WithMany(u => u.TransportRequests)
.HasForeignKey(tr => tr.UserId)
.HasConstraintName("FK_TRANSPORT_RQST_USER");
builder.Entity<TransportRequest>()
.HasOne(tr => tr.TransportAdvertise)
.WithMany(ta => ta.TransportRequests)
.HasForeignKey(tr => tr.TransportAdvertiseId)
.HasConstraintName("FK_TRANSPORT_RQST_ADS");
// TransportRoute model fks.
builder.Entity<TransportRoute>()
.HasOne(tr => tr.City)
.WithMany(c => c.TransportRoutes)
.HasForeignKey(tr => tr.CityId)
.HasConstraintName("FK_TRANSPORT_ROUTE_CITY");
builder.Entity<TransportRoute>()
.HasOne(tr => tr.TransportAdvertise)
.WithMany(ta => ta.TransportRoutes)
.HasForeignKey(tr => tr.TransportAdvertiseId)
.HasConstraintName("FK_TRANSPORT_ROUTE_ADS");
}
Vehicle Creation Code
[HttpPost]
public IActionResult AddNewVehicle(VehicleViewModel model)
{
var id = _userManager.GetUserId(User);
// model property check needs to be done before.
// vehicle table does not accept nulls.
var vehicle = new Vehicle()
{
Model = model.Model,
Capacity = model.Capacity,
Description = model.Description,
Year = model.Year,
Active = true,
Delete = false,
RecordDate = DateTime.Now,
UserId = id
};
_vehicleService.AddNew(vehicle);
return RedirectToAction("Index");
}
Do a simple experiment... Create a new user and note its Id... Immediately add a product and check again if the user ID has changed after the save operation. It is possible the user details is being mutated/changed upon save operation. You can also paste the code samples for creating a user, creating a product and retrieving a user here. The problem is most likely where u are saving the vehicles. At that point the user details is either being mutated, or the vehicles is being stored with a different user. The vehicles has a 1 to 1 relationship with the user. So when creating a vehicle be careful not to be doing vehicle.user = new User; Ensure you are doing the following.
1- Get the user from the Db :
var user = await UserManager.FindByIdAsync("Id of currently logged in
user");
2- set vehicle.user to the user retrieved above:
vehicle.user = user.
You can share code where u are saving vehicle for people to be able to help. Also you can prevent the user Id from being automatically generated in the db and add a [Required] attribute on the Id field. You can the do
user.Id = Guid.Guid.NewGuid()
. This can help prevent issues where a new user is automatically added to the db when u create a vehicle

Can't edit unique values

I have some difficulties with editing data. I have some property - ISBN. I put it to have a unique value. When I create new data it's ok but when I try to edit, it wrights that is already in use. What can I do?
Class Books:
[Remote("IsISBNExists", "Book", ErrorMessage = "ISBN number is already in use")]
public string ISBN { get; set; }
BookController:
public JsonResult IsISBNExists(string Isbn) {
return Json(!bookContext.Books.Any(x => x.ISBN == Isbn), JsonRequestBehavior.AllowGet);
}
You can include the ID of the record you are editing and use that to determine if the ISBN is in use..
Just add your Book ID field in the AdditionalFields parameter to include it in the validation request.
[Remote("IsISBNExists", "Book", AdditionalFields = "BookID", ErrorMessage = "ISBN number is already in use")]
public string ISBN { get; set; }
then use that field in your validation
public JsonResult IsISBNExists(string Isbn, int BookID) {
return Json(!bookContext.Books.Any(x => x.BookID != BookID && x.ISBN == Isbn), JsonRequestBehavior.AllowGet);
}

MVC Drop Down list with entity framework

I've created an MVC project using entity framework code first. My model is simply a form that gathers information.
public class Application
{
public int Id { get; set; }
public string FirstName { get; set; }
public string MiddleInitial { get; set; }
public string LastName { get; set; }
public int SSN { get; set; }
public DateTime DOB { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State {get; set; }
public string Zip { get; set; }
public int HomePhone { get; set; }
public int BusinessPhone { get; set; }
public int MobilePhone { get; set; }
}
My goal is to create a drop down list with all of the states, but I'm finding this to be very difficult given that I've already created the database via scaffolding with views and controllers. Is there a simple way to do this and tie it in with the existing database? I've searched for almost the entire day with no luck. An overview/explanation of what to include for the model/controller/view would be amazing!
Update: I've created a new model named "State" with properties "Id" and "StateName" and have created some states in the database. In my "Application" controller inside the Create action method I have:
Controller
public ActionResult Create()
{
ApplicationDbContext db = new ApplicationDbContext();
this.ViewData["Id"] = new SelectList(db.States.ToList(), "Id", "StateName");
return View();
}
View
#Html.DropDownList("Id")
Now the problem is I'm getting this error " There is no ViewData item of type 'IEnumerable' that has the key 'Id'." Would really appreciate help!
Its quite simple. Add an IEnumerable<SelectListItem> property to your model(Here I suggest you make a ViewModel that can have the exact same properties as Application with the below code included as a property). Then you just need to build the list and send it to your view
public IEnumerable<SelectListItem> States{ get; set; }
I will assume you want to retrieve the State values from the db. Here is how you will do it:
private IEnumerable<SelectListItem> GetAllStates()
{
IEnumerable<SelectListItem> list = from s in db.Applications
select new SelectListItem
{
Selected = false,
Text = s.State,
Value = s.State
};
return list;
}
Or this...
private IEnumerable<SelectListItem> GetAllStates()
{
IEnumerable<SelectListItem> list = db.Applications.Select(s => new SelectListItem
{
Selected = false,
Text = s.State,
Value = s.State
});
return list;
}
Then do something like this in your action:
var app = new Application
{
States = GetAllStates()
};
return View(app);
Then finally, use Razor on the view to display the Dropdown list like this
#Html.DropDownListFor(m => m.State, Model.States, "--Select a State--")
The 1st parameter is the property of the model to update, the 2nd is the list of data, and 3rd is the default message that will be displayed
Hope this helps.
Create a data layer that retrieves a list of what you want. Then use EF to get all the states.
//assuming you have a table of states..
var states = db.States();
The states table should be a Unique list of states.
var selectList = new List<SelectListItem>();
foreach(var thing in states){
//if you got everything, thus the ID field for the value...
selectList.Add(new SelectListItem {Text =thing.State, Selected = false, Value = thing.ID);
}
Make sure in your Viewmodel class that selectlist is a public property.....and set to what you did above. You also need to provied a string for the view selection post back.
StatesSelectList = selectList;
public IEnumberable<SelectListItem> StatesSelectList {get;set;}
public string SelectedState {get;set;}
In your view, do this:
#Html.DropDownListFor(p=>Model.SelectedState, Model.StatesSelectList)
Very simple Code step by step
1) In Entity Framework Class
var productsList = (from product in dbContext.Products
select new ProductDTO
{
ProductId = product.ProductId,
ProductName = product.ProductName,
}).ToList();
2) In Controller
ViewBag.productsList = new EntityFrameWorkClass().GetBusinessSubCategoriesListForDD();
3) In View
#Html.DropDownList("Product_ProductId", new SelectList(ViewBag.productsList, "ProductId", "ProductName"), new { #class = "form-control" })
OR
#Html.DropDownListFor(m=>m.Product_ProductId, new SelectList(ViewBag.productsList , "ProductId", "ProductName"), new { #class = "form-control" })
I assume there is a States model that has a Id and a StateName property.
Change to the list to ViewData["State"] to ensure easy binding on POST.
Id is the value that will be sent in the POST data ie.. State = Id. The StateName is what will be displayed in the Select list. So for your model this is not correct as State is a string. So needs to be
this.ViewData["State"] = new SelectList(db.States.ToList(), "StateName", "StateName");
Then in your view
#Html.DropDownList("State")

Model - field based on values in other fields

I've literally just started learning MVC.
I have created a simple model:
public class StaffMember
{
public Guid StaffMemberId { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public string Team { get; set; }
public virtual ICollection<Observation> Observations { get; set; }
}
Now I have decided that I want to include a drop down list of all StaffMembers on the create page for the observation records. I manage to do that with the following code:
#Html.DropDownListFor(o => o.StaffMemberId,
new SelectList(Model.StaffMembers,
"StaffMemberId",
"Forename",
Model.StaffMemberId),
"-- Select Staff Member --")
This works perfectly, although, you'll notice that I can only include a single field, "Forename".
I want the drop down list to show the staff member's full name. I tried concatenating the fields manually i.e. "Forename" + " " + "Surname" but that threw and exception about there being no such field as "Forename" + " " + "Surname".
My question is this - is it possible to add to my model some sort of property that is simply based on the value of two existing properties. Something like:
public class StaffMember
{
private string _fullName;
public Guid StaffMemberId { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public string Team { get; set; }
public virtual ICollection<Observation> Observations { get; set; }
public string FullName
{
get
{
return _fullName;
}
set
{
value = this.Forename + " " + this.Surname;
_fullName = value;
}
}
}
I tried the above, but when populating my database (I'm using entity model code first), that field always has a value of null, even though the field shows the correct value when debugging.
I'm using the following to auto populate the db with some test data:
var staff = new List<StaffMember>
{
new StaffMember
{
Forename = "Bob",
Surname = "Hope",
StaffMemberId = Guid.NewGuid(),
Team = "Test"
},
new StaffMember
{
Forename = "Stan",
Surname = "Laurel",
StaffMemberId = Guid.NewGuid(),
Team = "Test"
}
};
staff.ForEach(s => context.StaffMembers.Add(s));
context.SaveChanges();
Any pointers would be really useful here, especially if I am approaching this in completely the wrong way!
Yes, you're really close with the FullName property.
public class StaffMember
{
public string FullName
{
get
{
return this.Forename + " " + this.Surname;
}
}
}
No need for a private _fullName since you only need to get the values of Forename and Surname. And you don't need a set since you won't set a value back to this model using FullName
You can make this change in your Repository where you add Staff_Member
public void AddStaff(Staff_Member sm)
{
String fullName = sm.Forename.ToString()+" "+sm.Surname.ToString();
sm.FullName = fullName;
_context.Staff_Member.Add(sm);
}
However, you need to have set method for FullName as well in your Staff_Member model.

Resources