so I have 3 models :
public class Contact
{
public int ContactID { get; set; }
public string name { get; set; }
public int SegmentID { get; set; }
public Segment Segment { get; set; }
}
public class MedicalPlan
{
public int MedicalPlanID { get; set; }
public string name { get; set; }
public int SegmentID { get; set; }
public Segment Segment { get; set; }
}
public class Target
{
public int TargetID { get; set; }
public int MedicalPlanID { get; set; }
public int ContactID { get; set; }
public MedicalPlan MedicalPlan { get; set; }
public Contact Contact { get; set; }
}
A MedicalPlan got many Contacts, and Target got both many MedicalPlans and Contacts,
Now Each MedicalPlan has a buttom called generate: Example
What I want is when you press that buttom it creates a Target and generates every Contacts that are associated to that MedicalPlan through SegmentID and insert them in the table Target as shown here
I've tried something like this :
IEnumurable<int> cons =
from contact in contacts
where contact.SegmentID == planMedical.SegmentID
select contact.ContactID;
int[] res = cons.ToArray();
for ( int j = 0; j < res.Length ; j++)
{
targets.PlanMedicalID = id; //id MedicalPlans current row's key
targets.ContactID = res[j];
_context.Add(targets);
await _context.SaveChangesAsync();
}
But it does nothing..
You are creating you ViewModel which is PlanTargets, but you have to create you Database Model Entity, you have to create the object as:
for ( int j = 0; j < res.Length ; j++)
{
var target = new Target //ADD THIS LINE
{
MedicalPlanID = id,
ContactID = res[j]
};
_context.Target.Add(target);
_context.SaveChangesAsync();
}
You are not creating a Target object, you are creating a PlanTargets object and trying to add it to your DbContext.
NOTE: In your scenerio, you want to create a Target object for every ContactID, so in your for loop you have to create the object with the new keyword, and set the related properties, after that you have to add it to your DbContext, and when you SaveChanges then it will save the results to your database.
Related
I have a Cinema Model:
public class Cinema
{
public int Id { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
[Required]
public string Address { get; set; }
[Required]
[Range(0, int.MaxValue, ErrorMessage = "Please enter valid number")]
[Display(Name = "Total Seats")]
public int TotalSeatsNumber { get; set; }
public List<Seat>TotalSeats { get; set; }
public OpeningHour OpeningHour { get; set; }
[Required]
[Display(Name = "Opens At")]
public byte OpeningHourId { get; set; }
public ClosingHour ClosingHour { get; set; }
[Required]
[Display(Name = "Closes At")]
public byte ClosingHourId { get; set; }
public Cinema() { }
I have a TotalSeatsNumber property, so when the admin fills a form (Inside the website) to create a new cinema, he has to specify how many seats the cinema should contain.
I've also created a List of Seats called TotalsSeats, which later I try to initialize with seats according to the number of seats the admin chose. You can see what I'm trying to do here:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Save(Cinema cinema)
{
if (!ModelState.IsValid)
{
var viewModel = new CinemaFormViewModel(cinema)
{
OpeningHours = _context.OpeningHours.ToList(),
ClosingHours = _context.ClosingHours.ToList()
};
return View("CinemaForm", viewModel);
}
if (cinema.Id == 0)
{
cinema.TotalSeats = SetSeats(cinema.TotalSeatsNumber);
_context.Cinemas.Add(cinema);
}
else
{
var cinemaInDb = _context.Cinemas.Single(c => c.Id == cinema.Id);
cinemaInDb.Name = cinema.Name;
cinemaInDb.Address = cinema.Address;
cinemaInDb.TotalSeatsNumber = cinema.TotalSeatsNumber;
cinemaInDb.TotalSeats = cinema.TotalSeats;
cinemaInDb.OpeningHourId = cinema.OpeningHourId;
cinemaInDb.ClosingHourId = cinema.ClosingHourId;
}
_context.SaveChanges();
return RedirectToAction("Index", "Cinemas");
}
The SetSeats function returns a list of Seats where I initialize their Id, location, and availability. Just in case, I will add my Seat Model and SetSeats function here:
public class Seat
{
public int Id { get; set; }
[Required]
public string Location { get; set; }
[Required]
public bool isAvailable { get; set; }
public Seat()
{
isAvailable = true;
}
}
public List<Seat> SetSeats(int totalSeatsNumber)
{
List<Seat> totalSeats = new List<Seat>();
char rowLetter = 'a';
int seatNumInRow = 1;
for (int i = 1; i <= totalSeatsNumber; i++, seatNumInRow++)
{
totalSeats.Add(new Seat() { Id = i, Location = rowLetter + ("" + seatNumInRow), isAvailable = true });
if ((i % 10) == 0)
{
rowLetter++;
seatNumInRow = 0;
}
}
return totalSeats;
}
The reason I'm trying to do this is that I want that the user will be able to choose a specific seat when he orders tickets for a movie in a certain cinema.
The problem is when I try to SaveChanges(), it throws me an exception:
System.Data.Entity.Infrastructure.DbUpdateException: 'An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details.'
When debugging, I can see my "cinema" instance is updated properly, exactly like I wanted. But it fails when trying to save it to the DB.
your Seat class doesnt have any relations with Cinema class, but you are trying to add a list , so add a foreign key CinemaId
public class Seat
{
public int Id { get; set; }
......
public int CinemaId { get; set; }
public virtual Cinema Cinema {get; set;}
}
you will have to migrate to db after changing
You have to migrate first to make sure the database scheme go async with your DbModels in C#.
I am trying to input data using a loop. In the first loop it is able to succesfully input the data. In the second loop when it comes to saving the data it comes up with an error message
An exception of type 'System.InvalidOperationException' occurred in Microsoft.EntityFrameworkCore.dll
but was not handled in user code:
'The property 'userTask.TaskScheduleId' is part of a key and so cannot be modified or marked as modified.
To change the principal of an existing
entity with an identifying foreign key, first delete the dependent and invoke 'SaveChanges', and then
associate the dependent with the new principal.'
Here is the code below.
It creates a copy of the data in taskSchedule and then copies it to all the other users.
taskSchedule table has a many to many relationship with the users table which is why it is also saving data in the userTask table.
foreach(int user in users){
TaskSchedule copyTaskSchedule = new TaskSchedule();
copyTaskSchedule = taskSchedule;
copyTaskSchedule.Id = 0;
copyTaskSchedule.Notes = null;
copyTaskSchedule.UserTasks = null;
_context.TaskSchedules.Add(copyTaskSchedule);
_context.SaveChanges(); // this is where the code stops on the 2nd loop
// add updated user to the task
userTask copyUserTask = new userTask();
copyUserTask.TaskScheduleId = copyTaskSchedule.Id;
copyUserTask.UserId = user;
_context.userTasks.Add(copyUserTask);
_context.SaveChanges();
}
TaskSchedule model
public class TaskSchedule
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime? Start { get; set; }
public DateTime? End { get; set; }
public bool isClosed { get; set; }
public bool isDeleted { get; set; }
public byte priorityLevel { get; set; }
public bool hasTimeLimit { get; set; }
public Customer customer { get; set; }
public int? customerId { get; set; }
public List<Note> Notes { get; set; }
public List<AttachmentFile> Attachments { get; set; }
public List<userTask> UserTasks {get; set;}
public int? userLastEditId { get; set; }
[ForeignKey("userLastEditId")]
public User userLastEdit { get; set; }
public DateTime? userLastEditDate { get; set; }
public DateTime taskCreatedDate { get; set; }
}
looks like copyTaskSchedule.Id is a primary key or a foreign key . You are initializing the value to copyTaskSchedule.Id = 0;
I think you must change this code
copyUserTask.TaskScheduleId = copyTaskSchedule.Id;
to this
copyUserTask.TaskSchedule = copyTaskSchedule;
I removed the code below
copyTaskSchedule = taskSchedule;
Then replaced it with the following code below. I manually added each field from taskSchedule to copyTaskSchedule
copyTaskSchedule.Title = taskSchedule.Title;
copyTaskSchedule.Start = taskSchedule.Start;
copyTaskSchedule.End = taskSchedule.End;
copyTaskSchedule.userLastEditId = taskSchedule.userLastEditId;
copyTaskSchedule.priorityLevel = taskSchedule.priorityLevel;
copyTaskSchedule.isClosed = taskSchedule.isClosed;
copyTaskSchedule.hasTimeLimit = taskSchedule.hasTimeLimit;
copyTaskSchedule.Attachments = taskSchedule.Attachments;
copyTaskSchedule.customerId = taskSchedule.customerId;
copyTaskSchedule.userLastEditDate = NowDateTime;
copyTaskSchedule.isDeleted = taskSchedule.isDeleted;
copyTaskSchedule.taskCreatedDate = NowDateTime;
I have two objects with many to many relationship:
public class Order
{
public int OrderID { get; set; }
public string OrderName { get; set; }
public virtual Collection<Product> Products { get; set; } = new Collection<Product>();
}
public class Product
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public int OrderID { get; set; }
public virtual Collection<Order> Orders { get; set; } = new Collection<Order>();
}
// Mapping table
public class OrderProduct
{
public int OrderId { get; set; }
public Order Order { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
}
I would like to add a new Order with a collection of existing Products (my API would have an input of ProductID array) into the database, so I perform like:
private void AddOrder(int[] productIDs)
{
Order newOrder = new Order();
newOrder.Name = "New Order";
// Here I have no clue which would be the correct way...Should I do
// Approach A(fetch each related entity - Product from database then add them into the collection of my new base entity - Order):
productIDs.ToList().Foreach(p =>
{
newOrder.Products.Add(_dbContext.Product.FindById(p))
}
);
_dbContext.Orders.Add(newOrder);
var newOrderID = _dbContext.SaveChanges();
// then fetch each product from database and add my new Order to its collection and save
productIDs.ToList().Foreach(p =>
{
var existedProductFromDb = _dbContext.Product.FindById(p);
existedProductFromDb.Orders.Add(newOrder);
_dbContext.SaveChanges();
}
);
}
Do I really need the Mapping table between Order and Product in Entity Framework Core? Otherwise, what would be the correct way to deal with above scenario?
Your entities do not represent a many-to-many relationship using a joined table. In fact, you don't use the joining table at all.
So, start by fixing your entities:
public class Order
{
public int OrderID {get;set;}
public string OrderName {get;set;}
public ICollection<OrderProduct> Products { get; set; } = new HashSet<OrderProduct>();
}
public class Product
{
public int ProductID {get;set;}
public string ProductName {get;set;}
public ICollection<OrderProduct> Orders { get; set; } = new HashSet<OrderProduct>();
}
A new Order which contains many Products is as simple as a collection of new OrderProducts:
private void AddOrder(int[] productIDs)
{
Order newOrder = new Order();
newOrder.Name = "New Order";
foreach (int productId in productIDs)
{
newOrder.Products.Add(new OrderProduct { ProductId = productId });
}
_dbContext.Orders.Add(newOrder);
_dbContext.SaveChanges();
}
Also, do notice that SaveChanges returns the number of affected rows in the database, not the Id of an inserted item.
I'm working with EF5. I've used code first approach. I got an error while using stored procedure. The error is
"The entity type CustomProduct is not part of the model for the current context."
In Db there are 3 tables.
Product
ProductId
ProductName
ProductDesription
ProuctVaraint
ProductVaraintId
ProductId
ProductVaraintName
Stock
Size
ProductPrice
ProductPriceId
ProudctId
Price
and Each entity has separate class with having all properties.
Product.cs
ProductVaraint.cs
ProductPrice.cs
Here is all classes
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
}
public class ProductVaraint
{
public int ProductVaraintId { get; set; }
public int ProductId { get; set; }
public string ProdcutVaraintName { get; set; }
public int Stock { get; set; }
public int Size { get; set; }
}
public class ProductPrice
{
public int ProductPriceId { get; set; }
public int ProductId { get; set; }
public decimal Price { get; set; }
}
public class CustomProduct
{
public int ProudctId { get; set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public int Stock { get; set; }
public int Size { get; set; }
public decimal Price { get; set; }
}
Here is stored Procedure
public IList<CustomProduct> ExecuteSP()
{
var context = ((IObjectContextAdapter)(this)).ObjectContext;
var connection = this.Database.Connection;
//open the connection
if (connection.State == ConnectionState.Closed)
connection.Open();
//create a command object
using (var cmd = connection.CreateCommand())
{
//command to execute
cmd.CommandText = "GetProducts";
cmd.CommandType = CommandType.StoredProcedure;
var reader = cmd.ExecuteReader();
var result = context.Translate<CustomProduct>(reader).ToList();
for (int i = 0; i < result.Count; i++)
result[i] = AttachEntityToContext(result[i]);
reader.Close();
return result;
}
}
}
public TEntity AttachEntityToContext<TEntity>(TEntity entity) where TEntity : BaseEntity, new()
{
var alreadyAttached = Set<TEntity>().Local.Where(x => x.Id == entity.Id).FirstOrDefault();
if (alreadyAttached == null)
{
Set<TEntity>().Attach(entity);
return entity;
}
else
{
return alreadyAttached;
}
}
I've mapped Product.cs,ProductVaraint.cs and ProductPrice.cs with DBContext but not mapped CustomProduct.cs
Now, I've made one stored procedure to return ProductName(from Product),ProductDescription(from product),Stock(from ProductVaraint),Size(from ProductVaraint) and Price(from ProductPrice).
To map this properties, I've a separate class called CustomProudct.cs that contains all those properties which is return by the stored procedure and map this class with store procedure.
There is no separate table for CustomProduct and I don't need to create extra table only for mapping sp result.
I know the causes that there is no separate table of CustomProduct and EF is trying to search in Db for this table and it does not find any table that's why it is throwing exception.
Please anyone suggest me how to do this. Is there any other way to handle this type of situation?
You should have something like
List<CustomProduct> lst = new List<CustomProduct>();
while reader.Read()
{
CustomProduct cp = new CustomProduct();
cp.ProductName = reader.GetString(0); --where 0 is the column index
.....
lst.Add(cp);
}
I don't know what AttachEntityToContext does, but as the name suggests, you are trying to attach this CustomProduct to the DbContext. It will not work because this is a class you created, with no correspondent in the DB.
Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values.
ASP.NET MVC3 Entity framework 4.1
My MODEL
public class OrganizationStructure
{
public OrganizationStructure()
{
this.OrganizationStructures = new List<OrganizationStructure>();
InputDate = DateTime.Now;
}
public int ID { get; set; }
public string Name { get; set; }
public int OrganizationStructureID { get; set; }
public int OrganizationID { get; set; }
public int OrganizationTypeID { get; set; }
public int OrganizationActivityID { get; set; }
public int OrganizationLocationID { get; set; }
public string AddRemark { get; set; }
public int UserId { get; set; }
public DateTime InputDate { get; set; }
public int? RemAttr { get; set; }
public IList<OrganizationStructure> OrganizationStructures { get; private set; }
}
TABLE
ID int Unchecked
Name nvarchar(MAX) Checked
OrganizationID int Checked
OrganizationStructureID int Unchecked
OrganizationTypeID int Checked
OrganizationLocationID int Checked
OrganizationActivityID int Checked
AddRemark nvarchar(MAX) Checked
UserId int Checked
InputDate datetime Checked
RemAttr int Checked
public ICommandResult Execute(CreateOrUpdateOrganizationStructureCommand command)
{
var organizationStructure = new OrganizationStructure
{
ID = command.ID,
Name = command.Name,
OrganizationStructureID = command.OrganizationStructureID,
OrganizationID = command.OrganizationID,
OrganizationTypeID = command.OrganizationTypeID,
OrganizationActivityID = command.OrganizationActivityID,
OrganizationLocationID = command.OrganizationLocationID,
AddRemark = command.AddRemark,
UserId = command.UserId
};
if (organizationStructure.ID == 0)
_organizationStructureRepository.Add(organizationStructure);
else
_organizationStructureRepository.Update(organizationStructure);
_unitOfWork.Commit();
return new CommandResult(true);
}
The OrganizationStructureID property has to be nullable otherwise you will not be able to insert records with auto incremented primary keys.
EF will not be able to handle cyclic relationship even if you had OrganizationStructureID nullable. You need to save it in 2 steps.
using (var scope = new TransactionScope())
{
var context = new MyContext();
var organizationStructure = new OrganizationStructure {/* assign props */ };
context.OrganizationStructures.Add(organizationStructure);
context.SaveChanges(); // step 1
organizationStructure.OrganizationStructures.Add(organizationStructure);
context.SaveChanges(); // step 2
scope.Complete();
}