Entity Framework - Setting a "Nullable" integer to null - c#

I have a table in my DB called Login. In this table I have an attribute called Head_ID, which is nullable.
Basically, you can have a chief, or you ARE the chief. In the case that you're the chief, the Head_ID should be null. In my application I have the possibility to change one's chief (Coworker changes chief, chief gets downgraded and get's a chief above him), but this int won't be set to
Service.cs
public int EditLogin(LoginDTO login)
{
try
{
var dbLogin = DAO.HourRegInstance.Login.Single(x => x.ID == login.Id);
dbLogin.Name = login.Name;
dbLogin.Username = login.Username;
if (login.Head_Id == 0)
{
//Doesn't work
dbLogin.Head_ID = null;
}
dbLogin.Role_ID = login.Role_Id;
DAO.HourRegInstance.SaveChanges();
return 1;
} catch(Exception e){
return -1;
}
}
Login.cs
public partial class Login
{
public Login()
{
this.HourRegistrationConfirmed = new HashSet<HourRegistrationConfirmed>();
this.HourRegistrationConfirmed1 = new HashSet<HourRegistrationConfirmed>();
this.Login1 = new HashSet<Login>();
this.LoginProject = new HashSet<LoginProject>();
}
public long ID { get; set; }
public string Name { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public long Role_ID { get; set; }
public Nullable<long> Head_ID { get; set; }
public virtual ICollection<HourRegistrationConfirmed> HourRegistrationConfirmed { get; set; }
public virtual ICollection<HourRegistrationConfirmed> HourRegistrationConfirmed1 { get; set; }
public virtual ICollection<Login> Login1 { get; set; }
public virtual Login Login2 { get; set; }
public virtual Role Role { get; set; }
public virtual ICollection<LoginProject> LoginProject { get; set; }
}
How does one accomplish such task?

Solved the problem on my own.
I'm not sure what caused this problem, but after a restart of the service, everything seems to work alright now. Maybe just Entity Framework being Entity Framework?

Related

Entity Framework: How do I delete table rows that reference each other?

How do I delete the order without getting this exception?
UserLicenses references SerialOnOrderDetails and vice-versa:
The DELETE statement conflicted with the REFERENCE constraint "FK_SerialsOnOrderDetail_UserLicenses". The conflict occurred in database "sales", table "dbo.SerialsOnOrderDetail", column 'UserLicenseId'.
Delete confirmed controller action code:
[Authorize(Roles = "admin")]
[HttpPost, ActionName("Delete")]
public async Task<ActionResult> DeleteConfirmed(int id)
{
Order order = GetOrderById(id);
if (order.UserLicenses.Count > 0)
{
context.UserLicenses.RemoveRange(order.UserLicenses);
}
if (order.SerialsOnOrderDetails.Count > 0)
{
context.SerialsOnOrderDetails.RemoveRange(order.SerialsOnOrderDetails);
}
context.Orders.Remove(order);
context.SaveChanges(); // Exception here !!!
}
[EDIT] Added live data
Live data (Id = UserLicenseId):
Additional classes:
public partial class UserLicense
{
public string Id { get; set; }
public int OrderId { get; set; }
public string ProductId { get; set; }
public int CustomerId { get; set; }
public string AssignedUserId { get; set; }
public bool IsActive { get; set; }
public virtual AspNetUser AspNetUser { get; set; }
public virtual Customer Customer { get; set; }
public virtual Order Order { get; set; }
public virtual Product Product { get; set; }
public virtual ICollection<SerialsOnOrderDetail> SerialsOnOrderDetails { get; set; }
}
public partial class SerialsOnOrderDetail
{
public int orderID { get; set; }
public string serial { get; set; }
public string productID { get; set; }
public string UserLicenseId { get; set; }
public int customerID { get; set; }
public virtual Product Product { get; set; }
public virtual Serial Serial1 { get; set; }
public virtual Order Order { get; set; }
public virtual UserLicense UserLicense { get; set; }
public virtual Customer Customer { get; set; }
}
public partial class Order
{
public Order()
{
this.OrderDetails = new HashSet<OrderDetail>();
this.SerialsOnOrderDetails = new HashSet<SerialsOnOrderDetail>();
this.UserLicenses = new HashSet<UserLicense>();
}
public int orderID { get; set; }
public int customerID { get; set; }
public string promoCodeID { get; set; }
public System.DateTime date { get; set; }
public Nullable<int> resellerID { get; set; }
public string invoiceID { get; set; }
public string poNumber { get; set; }
public Nullable<System.DateTime> paymentDate { get; set; }
public Nullable<bool> validated { get; set; }
public string resellerOrderID { get; set; }
public Nullable<int> parentOrderID { get; set; }
public int months { get; set; }
public virtual Customer Customer { get; set; }
public virtual ICollection<OrderDetail> OrderDetails { get; set; }
public virtual PromoCode PromoCode { get; set; }
public virtual Reseller Reseller { get; set; }
public virtual ICollection<SerialsOnOrderDetail> SerialsOnOrderDetails { get; set; }
public virtual Order ParentOrder { get; set; }
public virtual ICollection<UserLicense> UserLicenses { get; set; }
}
Did you verify if UserLicenses and SerialsOnOrderDetails collections are properly loaded and not empty ? Are you sure removerange is the proper way to do it ? I suggest you to read a few tutorials about EF if you are not used to it.
Maybe you'll have to update GetOrderById with .Include("....") directives to load these collections, or load the related items manually.
That constraint message you quote is from the underlying SQL Server. It's not an EF error as such, it's passed through.
When I get this sort of problem in TSQL the solution is generally to delete both of the mutually referencing rows in a single transaction.
While I'm not terribly familiar with EF, a quick search turn up this example of putting multiple operations into a single transactional context instead of the default behaviour of a single transaction per operation.
{
context.Database.Log = Console.WriteLine;
using (DbContextTransaction transaction = context.Database.BeginTransaction())
{
try
{
Author author1 = new Author() { Name = "Mark" };
Author author2 = new Author() { Name = "John" };
context.Authors.Add(author1);
context.SaveChanges();
context.Authors.Add(author2);
context.SaveChanges();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
}
}
}
I notice another respondent describes other things that could be wrong. It is entirely possible that we are both right and there are multiple issues to resolve.

Entity Framework: Can't save data because of tracking

I have got a complex class. Feedback and Steps. I am using SQL database and .NET Core 2. I can save main properties but can't save the sub class FeedbackSteps properties
public class FeedbackModel
{
[Key]
public int FeedBackID { get; set; }
public DateTime FBDate { get; set; }
public bool? VideoStatus { get; set; }
public string VideoDetail { get; set; }
public string PITFeedBack { get; set; }
public int ActivityID { get; set; }
public virtual ActivityModel Activity { get; set; }
public int ClientID { get; set; }
public virtual ClientModel Client { get; set; }
public int? SupportPlanID { get; set; }
public virtual SupportPlanModel SupportPlan { get; set; }
public int EmployeeID { get; set; }
public virtual Employee Employee { get; set; }
public bool FeedbackStatus { get; set; } = true;
virtual public List<FeedbackStepModel> FeedbackSteps { get; set; }
}
public class FeedbackStepModel
{
[Key]
public int FeedbackStepID { get; set; }
public int FeedbackID { get; set; } = 0;
public int SupportPlanID { get; set; }
public int StepNumber { get; set; }
public string StepDetail { get; set; }
public string AchievementStatus { get; set; }
public string AchievementComment { get; set; }
}
This is the post method. View returns Edited or Updated feedback and i just want to update the database with new data
[HttpPost]
public IActionResult Edit(FeedbackModel feedback)
{
if (ModelState.IsValid)
{
feedbackRepository.Save(feedback);
TempData["message"] = $"Feedback has been saved";
return RedirectToAction("Index");
}
}
After EDIT, I would like to save it...
public void Save(FeedbackModel feedback)
{
if (feedback.FeedBackID == 0)
{
context.FeedbackModels.Add(feedback);
}
else
{
FeedbackModel dbEntry = context.FeedbackModels.Include(s => s.FeedbackSteps).FirstOrDefault(a => a.FeedBackID == feedback.FeedBackID);
if (dbEntry != null)
{
dbEntry.FeedBackID = feedback.FeedBackID;
dbEntry.FBDate = feedback.FBDate;
dbEntry.VideoStatus = feedback.VideoStatus;
dbEntry.VideoDetail = feedback.VideoDetail;
dbEntry.SupportPlanID = feedback.SupportPlanID;
dbEntry.ActivityID = feedback.ActivityID;
dbEntry.PITFeedBack = feedback.PITFeedBack;
dbEntry.ClientID = feedback.ClientID;
dbEntry.EmployeeID = feedback.EmployeeID;
dbEntry.FeedbackStatus = feedback.FeedbackStatus;
dbEntry.FeedbackSteps = feedback.FeedbackSteps;
}
}
context.SaveChanges();
}
But I get this error all the time
The instance of entity type 'FeedbackStepModel' cannot be tracked because another instance with the key value '{FeedbackStepID: 1}' is already being tracked.
When attaching existing entities, ensure that only one entity instance with a given key value is attached.
Your FeedbackModel update operation with children (FeedbackSteps) should be as follows:
FeedbackModel dbEntry = context.FeedbackModels.Include(s => s.FeedbackSteps).FirstOrDefault(a => a.FeedBackID == feedback.FeedBackID);
if (dbEntry != null)
{
dbEntry.FeedBackID = feedback.FeedBackID;
dbEntry.FBDate = feedback.FBDate;
dbEntry.VideoStatus = feedback.VideoStatus;
dbEntry.VideoDetail = feedback.VideoDetail;
dbEntry.SupportPlanID = feedback.SupportPlanID;
dbEntry.ActivityID = feedback.ActivityID;
dbEntry.PITFeedBack = feedback.PITFeedBack;
dbEntry.ClientID = feedback.ClientID;
dbEntry.EmployeeID = feedback.EmployeeID;
dbEntry.FeedbackStatus = feedback.FeedbackStatus;
dbEntry.FeedbackSteps.Clear(); // First you have to clear the existing feedBackSteps
foreach(FeedbackStep feedBackStep in feedback.FeedbackSteps)
{
dbEntry.FeedbackSteps.Add(feedBackStep); // You have to add new and updated feedBackStep here.
}
}
If dbEntry.FeedbackSteps.Clear(); does not work (may be in EF Core 2.0 or lower Clear() does not work) then replace dbEntry.FeedbackSteps.Clear(); with the following code:
foreach(FeedbackStep feedbackStepToBeRemoved in dbEntry.FeedbackSteps)
{
context.Remove(feedbackStepToBeRemoved);
}

Retrieving data from multiple tables through Get() method in web API

I have just started with web API and got my first Get method successfully implemented. I was able to retrieve the data and show it to the client. Now I have to retrieve data from two tables through a single Get method which I am not able too. Here's my code for retrieving data from a single table.
public HttpResponsemessage Get(string Login, string Password)
{
using (Accord_BMHEntities entities = new Accord_BMHEntities())
{
Login = Login.Trim();
EncryptDecrypt EncryptDecryptObj = new EncryptDecrypt();
string EncryptedPassword =
EncryptDeccrypt.Encrypt(Login.Trim().ToUpper(), Password);
var userLogin = entities.ITPLUsers.firstOrDefault(e => e.Login == Login
& e.Password == EncryptedPassword
if (UserLogin == null)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound)
}
else
{
return Request.CreateResponse(HttpStatusCode.OK , UserLogin)
}
}
}
EmpMaster.cs
public partial class EmpMaster
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", n
CA2212:DoNotCallOverridableMethodsInConstructors")]
Public EmpMaster()
{
this.EmpPersonal = new HashSet<EmpPersonal>();
}
Public int EmployeeID { get; set; }
Public int DivisionId { get; set; }
Public int ResumeId { get; set; }
Public int GroupId { get; set; }
Public int DepartmentId { get; set; }
Public int WorkplaceId { get; set; }
Public int DesignationId { get; set; }
Public int Code { get; set; }
Public int DesignationId { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", n
CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICOllection<EmpPersonal> EmpPersonals { get; set; }
}
EmpPersonal.cs
Public partial class EmpPersonal
{
Public int EmployeeID { get; set; }
Public int DivisionID { get; set; }
Public short Gender { get; set; }
Public short BloodGroup { get; set; }
Public string FlatNo { get; set; }
Public string Premises { get; set; }
Public string Street { get; set; }
Public string Area { get; set; }
Public string City { get; set; }
Public string StateId { get; set; }
Public string CountryId { get; set; }
Public virtual EmpMaster EmpMaster { get; set; }
}
Please note : there are many more properties in both the class. Just to save time i have mentioned some of it.
If you have modeled the relation between the entities, you could use the Entity Framweork Include method (for eager loading) or Load method (for lazy loading).
Docs here: Entity Framework Loading Related Entities
Otherwise you could return an anonymous type:
var userLogin = entities.ITPLUsers.firstOrDefault(e => e.Login == Login
& e.Password == EncryptedPassword;
var empPersonal = entities.EmpPersonal.Where(....your condition...);
if (UserLogin == null)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound)
}
else
{
return Request.CreateResponse(HttpStatusCode.OK,new {userlogin = UserLogin, empPersonal = empPersonal});
}
I assume you want user address from Address entity along with user data. You have 2 options here. You can either use linq and join to get all related data with one query or you can get user and address datas one by one. In the end, you need to consolidate the data and return one result set since you want to return all of them in a single response.
You obviously need a resultModel for your endpoint.
Like;
public class UserResultModel
{
//Properties from User entity
public int Id { get; set; }
public string Username { get; set; }
//Properties from Address entity
public string City { get; set; }
}
You need to fill this resultModel and return it.
Irrelevant suggestion: I suggest not to check user's authentication like that. MVC has a really nice feature called Filters(Authorization Filters for more detailed)
Try Linq with joins by matching keys. You will get an example from msdn site.Msdn site

How do I post a one-to-many relationship?

Pretty new to ASP.NET and programming. I have two models, two API controllers, two repositories. How do I post the data to the second model while attaching it to the first (I'm guessing by ID.) Do I possibly need a View Model? Also reading a little about unit of work. Maybe neither are necessary? Below is some code. Thanks!
Record.cs
namespace Train.Models {
public class Record {
public int Id { get; set; }
public int Quantity { get; set; }
public DateTime DateCreated { get; set; }
public bool IsActive { get; set; }
public string UserId { get; set; }
public virtual ICollection<Cars> Cars { get; set; }
}
}
Cars.cs
namespace Train.Models {
public class Cars {
public int Id { get; set; }
public string EmptyOrLoaded { get; set; }
public string CarType { get; set; }
//Hopper, flatbed, tank, gondola, etc.
public string ShippedBy { get; set; }
//UP(Union Pacific) or BNSF
public string RailcarNumber { get; set; }
//public virtual ApplicationUser ApplicationUser { get; set; }
public string UserId { get; set; }
public string RecordId { get; set; }
public virtual Record Record { get; set; }
}
}
Record Repository
public void SaveRecord(Record recordToSave) {
if (recordToSave.Id == 0) {
recordToSave.DateCreated = DateTime.Now;
_db.Record.Add(recordToSave);
_db.SaveChanges();
} else {
var original = this._db.Record.Find(recordToSave.Id);
original.Quantity = recordToSave.Quantity;
original.IsActive = true;
_db.SaveChanges();
}
}
EFRepository (Cars)
public void SaveCar(Cars carToSave) {
if (carToSave.Id == 0) {
_db.Cars.Add(carToSave);
_db.SaveChanges();
} else {
var original = this.Find(carToSave.Id);
original.EmptyOrLoaded = carToSave.EmptyOrLoaded;
original.CarType = carToSave.CarType;
original.ShippedBy = carToSave.ShippedBy;
original.RailcarNumber = carToSave.RailcarNumber;
_db.SaveChanges();
}
}

ASP.NET MVC /Entity Framework Error - Invalid column name 'Environment_Id'

I'm new to ASP.NET MVC and EF hopefully this is not a silly question
When i pass model to view i'm getting this error - Exception Details: System.Data.SqlClient.SqlException: Invalid column name 'Environment_Id'.
Model nor database table has a property by that name. Could any guide me on this?.
**Here is the Version Model Class**
public partial class Version
{
public Version()
{
this.ProfileVersions = new List<ProfileVersion>();
this.ServerInfoes = new List<ServerInfo>();
}
public int Id { get; set; }
public string Number { get; set; }
public string Tag { get; set; }
public string Owner { get; set; }
public string Approver { get; set; }
public string Description { get; set; }
public virtual ICollection<ProfileVersion> ProfileVersions { get; set; }
public virtual ICollection<ServerInfo> ServerInfoes { get; set; }
}
**Profile Version Class**
public partial class ProfileVersion
{
public ProfileVersion()
{
this.PlatformConfigurations = new List<PlatformConfiguration>();
}
public int Id { get; set; }
public int ProfileId { get; set; }
public int EnvironmentId { get; set; }
public int VersionId { get; set; }
public Nullable<bool> Locked { get; set; }
public string LockedBy { get; set; }
public string Comments { get; set; }
public Nullable<int> Active { get; set; }
public virtual Environment Environment { get; set; }
public virtual ICollection<PlatformConfiguration> PlatformConfigurations { get;
set; }
public virtual PlatformProfile PlatformProfile { get; set; }
public virtual Version Version { get; set; }
}
**ServerInfo**
public partial class ServerInfo
{
public ServerInfo()
{
this.PlatformConfigurations = new List<PlatformConfiguration>();
}
public int Id { get; set; }
public string ServerName { get; set; }
public int ProfileId { get; set; }
public int VersionId { get; set; }
public int EnvironmentId { get; set; }
public string ServerType { get; set; }
public Nullable<short> Active { get; set; }
public string Domain { get; set; }
public string Location { get; set; }
public string IP { get; set; }
public string Subnet { get; set; }
public string Gateway { get; set; }
public Nullable<int> VLan { get; set; }
public string DNS { get; set; }
public string OS { get; set; }
public string OSVersion { get; set; }
public string Func { get; set; }
public Nullable<short> IISInstalled { get; set; }
public string ADDomainController { get; set; }
public string ADOrganizationalUnit { get; set; }
public string ADGroups { get; set; }
public string LastError { get; set; }
public Nullable<System.DateTime> LastUpdate { get; set; }
public virtual Environment Environment { get; set; }
public virtual ICollection<PlatformConfiguration> PlatformConfigurations { get;
set; }
public virtual PlatformProfile PlatformProfile { get; set; }
public virtual Version Version { get; set; }
public virtual VMConfiguration VMConfiguration { get; set; }
}
**Controller Code-**
public ViewResult Index(string id )
{
var profileVerList = from ver in _context.Versions
where !(from pfv in _context.ProfileVersions
select pfv.VersionId).Contains(ver.Id)
select ver;
var bigView = new BigViewModel
{
VersionModel = profileVerList.ToList(),
};
return View(model: bigView);
}
**In the View where the exception is thrown**
#Html.DropDownList(
"SelectedVersionID",
new SelectList(
Model.VersionModel.Select(x => new { Value = x.Id, Text = x.Number}),
"Value",
"Text"
)
)
In your ProfileVersion and ServerInfo entities you have an Environment navigation property. By default, Entity Framework will try to create a database column called [Property Name]_[Referenced class PK]. In your scenario, that's Environment_Id. The problem, right now, is that you have not done a migration to have this database column created.
If I had to imagine what happened here, I'd say you first created the classes with EnvironmentId properties, migrated, then later decided to add the navigation properties, Environment to each, expecting EF to associate that with your existing EnvironmentId properties. That's where you went wrong. As I said above, EF convention is to look for a database column named Environment_Id, so if you want EF to use EnvironmentId instead, you just need to tell it so with the ForeignKey data annotation:
[ForeignKey("Environment")]
public int EnvironmentId { get; set; }
In My Case I have added My Primary Key Relationship to Same Key .. SO I have simply remove..
I realize this question is 3 years old now, but I saw a different reason for the error - both in the original question and in my own code that was pretty similar. And, in my case, I had the same error as stated above.
I had a "MY_ACTIONS" table with an ID and Name pair that I wanted to be added to a dropdown. Here's the model:
namespace TestSite.Models
{
public class MY_ACTIONS
{
//[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public MY_ACTIONS()
{
this.o_actions = new HashSet<MY_ACTIONS>();
}
[Key]
public int action_id { get; set; }
[StringLength(100)]
public string action_name { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<MY_ACTIONS> o_actions { get; set; }
}
}
And to get an action to display on the dropdown it had an ID set in an int field called LASTACTION in my main table. In that model I had declared the ForeignKey relationship:
namespace TestSite.Models
{
[Table("MAIN_TABLE")]
public partial class MAIN_TABLE
{
[Key]
public int MAIN_TABLE_ID { get; set; }
public int LASTACTION { get; set; } // this would carry a number matching action_id
[ForeignKey("LASTACTION")]
public virtual MY_ACTIONS MY_ACTIONS { get; set; }
}
}
I had the error Invalid column name 'MY_ACTIONS_action_id' when loading this dropdown in my view:
#Html.DropDownList("lastaction", null, htmlAttributes: new { #class = "form-control" })
...for which I was using this ViewBag in my Controller function:
Model1 db = new Model1(); // database context
MAIN_TABLE o_main = new MAIN_TABLE();
o_main.lastaction = 2;
ViewBag.lastaction = new SelectList(db.MY_ACTIONS, "action_id", "action_name", o_main.lastaction);
If I did not have my FK relationship declared:
[ForeignKey("LASTACTION")]
public virtual MY_ACTIONS MY_ACTIONS { get; set; }
I probably also would've had the same issue. Having the representation of a virtual instance requires linking it with some physical property. This is similar to how this:
public virtual Environment Environment { get; set; }
Should be:
[ForeignKey("EnvironmentId")]
public virtual Environment Environment { get; set; }
in the ProfileVersion class, in the question, above, assuming that EnvironmentId is the Primary Key in a table called Environment (that model is not shown above).
For me, though, I already had that and I was still getting the error, so doing that still might not solve everything.
Turns out all I had to do was get rid of that ICollection<MY_ACTIONS> o_actions in the MY_ACTIONS model and the this.o_actions = new HashSet<MY_ACTIONS>(); line and it all went through fine.
There are many such lists and ICollections in play in the question above, so I would wager something is wrong with having them, as well. Start with just a plain model that represents the fields, then add in your virtual objects that represent tables linked to with foreign keys. Then you make sure your dropdown loads. Only after that should you start adding in your ICollections, HashSets, Lists<T> and other such amenities that are not actually physically part of the database - this can throw off Entity Framework into thinking it needs to do something with them that it doesn't need to do.

Categories