I have an object, called Order, which has several properties which are also objects. when I update the Order object the simple properties are updated correctly, but the complex ones (which reside in different tables) are not being updated and instead new ones are created. What am I doing wrong. Also, when I try to get a multiple items property (Items in this example) it returns null and not the saved items.
Code Sample:
[DataContract]
public class Order
{
[Key]
[DataMember]
public int Id { get; set; }
#region Order Details
[DataMember]
public int? ReferenceNumber { get; set; }
[DataMember]
public virtual Status CurrentStatus { get; set; }
[DataMember]
public DateTime? CurrentStatusUpdatedOn { get; set; }
[DataMember]
[MaxLength(1024)] public string ArchiveFileName { get; set; }
[DataMember]
public double TotalPrice { get; set; }
[DataMember]
public bool DigitallySigned { get; set; }
[DataMember]
public int DigitalSigningReferenceId { get; set; }
[DataMember]
public virtual Priority Priority { get; set; }
[DataMember]
public virtual ICollection<Item> Items { get; set; }
.....
}
[DataContract]
public class Item : IItem
{
[DataMember]
[Key]
public int Id { get; set; }
[DataMember]
public virtual Order ParentOrder { get; set; }
[DataMember]
public virtual ItemType Type { get; set; }
[DataMember]
public string ItemReference { get; set; }
[DataMember]
public int FeeReference { get; set; }
[DataMember]
public int Quantity { get; set; }
[DataMember]
public decimal Price { get; set; }
[DataMember]
public string Name { get; set; }
....
}
private static bool UpdateOrderDetails(Order order, DatabaseContext context)
{
var savedOrder =
context.Orders.Include("Priority").Include("CurrentStatus").Where(o => o.Id == order.Id).FirstOrDefault();
//context.Orders.SingleOrDefault(o => o.Id == order.Id);
if (savedOrder != null)
{
savedOrder.Priority = order.Priority;
savedOrder.ReferenceNumber = order.ReferenceNumber;
savedOrder.ShohamId = order.ShohamId;
savedOrder.TotalPrice = order.TotalPrice;
savedOrder.UpdatedOn = DateTime.Now;
savedOrder.CreatedOn = order.CreatedOn;
savedOrder.ArchiveFileName = order.ArchiveFileName;
savedOrder.ClientEmail = order.ClientEmail;
savedOrder.ClientFirstName = order.ClientFirstName;
savedOrder.ClientIdentificationNumber = order.ClientIdentificationNumber;
savedOrder.ClientIdentificationType = order.ClientIdentificationType;
savedOrder.ClientLastName = order.ClientLastName;
savedOrder.ClientPrimaryPhone = order.ClientPrimaryPhone;
savedOrder.ClientSecondaryPhone = order.ClientSecondaryPhone;
savedOrder.CurrentStatus = order.CurrentStatus;
savedOrder.CurrentStatusUpdatedOn = order.CurrentStatusUpdatedOn;
savedOrder.DigitallySigned = order.DigitallySigned;
savedOrder.DigitalSigningReferenceId = order.DigitalSigningReferenceId;
if (order.Items != null)
{
foreach (var item in order.Items)
{
var savedItem = savedOrder.Items.Single(x => x.ItemReference == item.ItemReference);
if (savedItem != null)
{
savedItem.Price = item.Price;
savedItem.Quantity = item.Quantity;
}
}
}
context.Entry(savedOrder).State = EntityState.Modified;
var i = context.SaveChanges();
If you don't want to insert new objects for your navigation properties you must attach them to the context before you assign the values. For your items collection problem you need to include the collection when you query. Including the other two navigation properties is not necessary and setting the state to Modified manually neither in your example. For Include you can use a strongly typed version in EF 4.1 with a lambda expression:
private static bool UpdateOrderDetails(Order order, DatabaseContext context)
{
var savedOrder = context.Orders.Include(o => o.Items)
.Where(o => o.Id == order.Id)
.FirstOrDefault();
if (savedOrder != null)
{
context.Priorities.Attach(order.Priority);
context.CurrentStati.Attach(order.CurrentStatus);
savedOrder.Priority = order.Priority;
// etc.
var i = context.SaveChanges();
}
}
Related
This is my Entity model class which was auto generated by Ado.net model
public partial class SubModule
{
public int SubModuleId { get; set; }
public Nullable<int> ModuleId { get; set; }
public string SubModuleName { get; set; }
public Nullable<bool> Active { get; set; }
public Nullable<bool> IsModules { get; set; }
public string url { get; set; }
public string path { get; set; }
public string subform { get; set; }
}
this is my another class
public class ChildModules
{
public int ? SubModuleId { get; set; }
public Nullable<int> ModuleId { get; set; }
public string SubModuleName { get; set; }
public Nullable<bool> Active { get; set; }
public Nullable<bool> IsModules { get; set; }
public string url { get; set; }
public string path { get; set; }
public string subform { get; set; }
}
I want to copy Sub modules data to my Child modules class properties
My code is
List<SubModule> ChildModule = entity.SubModules.Where(x => x.IsModules == false).ToList();
List<ChildModules> listchildmodules = new List<ChildModules>();
ChildModules chmodule = new ChildModules();
foreach (SubModule mod in ChildModule)
{
chmodule.SubModuleId = mod.SubModuleId;
chmodule.ModuleId = mod.ModuleId;
chmodule.SubModuleName = mod.SubModuleName;
chmodule.Active = mod.Active;
chmodule.IsModules = mod.IsModules;
chmodule.url = mod.url;
chmodule.path = mod.path;
chmodule.subform = mod.subform;
listchildmodules.Add(chmodule);
}
but in listchildmodules last row insert in every index.
Why?
Your code always add the same object always. Because you always updating the values of same object and insert that into list.
Keep the below line of code inside foreach.
ChildModules chmodule = new ChildModules();
Your foreach should look like below
foreach (SubModule mod in ChildModule)
{
ChildModules chmodule = new ChildModules();
chmodule.SubModuleId = mod.SubModuleId;
chmodule.ModuleId = mod.ModuleId;
chmodule.SubModuleName = mod.SubModuleName;
chmodule.Active = mod.Active;
chmodule.IsModules = mod.IsModules;
chmodule.url = mod.url;
chmodule.path = mod.path;
chmodule.subform = mod.subform;
listchildmodules.Add(chmodule);
}
Or you could declare ChildModules chmodule; outside foreach and initialize chmodule = new ChildModules(); inside foreach loop.
I've got this class
public class Materiale
{
public string IdMateriale { get; set; }
public string GenereMateriale { get; set; }
public string Categoria { get; set; }
public string Modello { get; set; }
public string Tipo { get; set; }
public string NumSerie { get; set; }
public int Anno { get; set; }
public string DittaCostruttrice { get; set; }
public string Note { get; set; }
public List<Controllo> Controlli = new List<Controllo>();
}
public class Controllo
{
public string IdControllo { get; set; }
public DateTime DataControllo { get; set; }
public string IdMateriale { get; set; }
public string Utente { get; set; }
public string Stato { get; set; }
public string Note { get; set; }
}
I want to query a list of "Materiale" filtering "Controlli". I need to retrieve all properties of the "Materiale" class and only one property of the "Controllo" class (the one named "Stato"). From the list "Controlli" I need the one that has the most recent "DataControllo" property.
I try this in a LINQ query but I receive an error (Max doesn't exist in the current context)
List<Materiale> m = new List<Materiale>();
List<Materiale> m2 = (from ma in m
from c in ma.Controlli
where c.DataControllo == Max(c.DataControllo)
select new
{
ma, c.Stato
}).ToList();
Can someone help me
#Christos is correct, here is my version with let in query syntax:-
List<Materiale> m2 = from m in MaterialeList
let RecentControllo = m.OrderByDescending(x => x.DataControllo)
.FirstOrDefault()
select new Materiale
{
IdMateriale = m.IdMateriale,
GenereMateriale = m.GenereMateriale,
//Similarily other properties of Materiale here
Stato = RecentControllo != null ? RecentControllo.Stato : ""
}).ToList();
I think that you need something more simple like the following one:
List<Materiale> m2 = from ma in m
let mostRecentControllo = ma.Controlli
.OrderByDescending(c=>c.DataControllo)
.FirstOrDefault()
select new
{
Materiale = ma,
Stato = mostRecentControllo != null
? mostRecentControllo.Stato : null
}).ToList();
I have supposed that each Materiale's Controlli list contains Controllo with the same IdMateriale.
I have object like this. This include Group Question (QG), 1 group question has many Question(Q), 1 question has many answer.
public class CrmQuestionAnswer
{
public long QgId { get; set; }
public string QgName { get; set; }
public int QgMIndex { get; set; }
public int QgMdf { get; set; }
public string QgDescription { get; set; }
public long QId { get; set; }
public long QParentId { get; set; }
public string QName { get; set; }
public string QDescription { get; set; }
public int QMindex { get; set; }
public int QMdf { get; set; }
public bool IsMainQuestion { get; set; }
public bool IsTitle { get; set; }
public int QTypeId { get; set; }
public long AnswerId { get; set; }
public string AnswerName { get; set; }
public string AnswerValue { get; set; }
public int AnswerMdf { get; set; }
public int AnswerMIndex { get; set; }
public string AnswerDescription { get; set; }
public long? LinkQuestionId { get; set; }
}
I want to use Linq to map List CrmQuestionAnswer to List QuestionGroupView
public class QuestionGroupView:Title
{
public List<CrmQuestionView> Questions;
}
public class CrmQuestionView: Title
{
public long? ParentId;
public bool? IsMainQuestion;
public bool? IsTitle;
public long? LinkQuestionId;
public List<CrmAnswerView> Answers;
}
public class CrmAnswerView : Title
{
public long? LinkQuestionId;
}
Title is base class:
public class Title
{
public long Id { get; set; }
public string Name { get; set; }
public int MIndex { get; set; }
public int Mdf { get; set; }
public int Type { get; set; }
public string Description { get; set; }
}
I use this code:
public List<QuestionGroupView> GetListQuestionsAnswers(long themaId)
{
var questionAnswerDao = new CrmQuestionAnswerDao();
var questionAnswerlist = questionAnswerDao.GetByThemasId(themaId);
//map List CrmQuestionAnswer -> List QuestionGroupView: 3 level
var listquestiongroup = questionAnswerlist
.OrderBy(t => t.QgMIndex)
.ThenBy(t => t.QMindex)
.GroupBy(t => t.QgId)
.Select(GetQuestionGroup)
.ToList();
return listquestiongroup;
}
private static QuestionGroupView GetQuestionGroup(IGrouping<long, CrmQuestionAnswer> grouping)
{
var group = grouping.First();
var question = new QuestionGroupView
{
Id = group.QgId,
Name = group.QgName,
Description = group.QgDescription,
Mdf = group.QgMdf,
MIndex = group.QgMIndex,
Questions = grouping
.Select(p => new CrmQuestionView
{
Id = p.QId,
Name = p.QName,
Description = p.QDescription,
Mdf = p.QMdf,
MIndex = p.QMindex,
Type = p.QTypeId,
ParentId = p.QParentId,
IsMainQuestion = p.IsMainQuestion,
IsTitle = p.IsTitle,
Answers = grouping//**This line is wrong**
.GroupBy(g => g.QId)
.Select(GetTitle)
.ToList()
})
.ToList()
};
return question;
}
private static CrmAnswerView GetTitle(IGrouping<long, CrmQuestionAnswer> grouping)
{
var group = grouping.First();
var answer = new CrmAnswerView
{
Id = group.AnswerId,
Name = group.AnswerName,
Description = group.AnswerDescription,
MIndex = group.AnswerMIndex,
Mdf = group.AnswerMdf,
Type = group.QTypeId,
LinkQuestionId = group.LinkQuestionId,
};
return answer;
}
This is data get from server Data
My code gets right Group question (2 group) with right List question, but it gets wrong list answer from data.
Can some help me ?
Best regards
While coding I had came across a LINQ query that I was able to accomplish in query syntax but not in lamda syntax. While this works fine in the application, I wanted to learn the query syntax for what I was trying to do.
Essentially, I have a database with views, CO_Leather_V and CO_LeatherSizeColor_V. I also have two classes, CuttingOrder and CuttingOrderDetail. CuttingOrderDetail contains entirely string,int and float properties. The CuttingOrder Class contains 2 string properties and a List of CuttingOrderDetails.
public class CuttingOrder
{
public string cuttingOrderNo { get; set; }
public string reserveSalesOrderNo { get; set; }
public List<CuttingOrderDetail> details { get; set; }
}
public class CuttingOrderDetail
{
public string cuttingOrderNo { get; set; }
public string reserveSalesOrderNo { get; set; }
public string itemCode { get; set; }
public string material { get; set; }
public string color { get; set; }
public string size { get; set; }
public int qty { get; set; }
public float squareFeet { get; set; }
public float squareFeetUsed { get; set; }
}
The query expression I used to get a list of all CuttingOrders with a given SalesOrder was
cos = (from l in db.CO_Leather_Vs
where l.orderNo == Globals.orderNo
select new Globals.CuttingOrder
{
cuttingOrderNo = "NOT SET",
reserveSalesOrderNo = "FAKE_SO_NO",
details = (
from d in db.CO_LeatherSizeColor_Vs
select new Globals.CuttingOrderDetail
{
cuttingOrderNo = d.orderNo
}
).ToList()
}).ToList();
I converted this to work in LINQPad with the following query, but I can't get anything to show on the lambda pane.
void Main()
{
var p = (from l in CO_Leather_V
select new CuttingOrder
{
cuttingOrderNo = "NOT SET",
reserveSalesOrderNo = "FAKE_SO_NO",
details = (
from d in CO_LeatherSizeColor_V
select new CuttingOrderDetail
{
cuttingOrderNo = d.OrderNo
}
).ToList()
}).ToList();
p.Dump();
}
// Define other methods and classes here
public class CuttingOrder
{
public string cuttingOrderNo { get; set; }
public string reserveSalesOrderNo { get; set; }
public List<CuttingOrderDetail> details { get; set; }
}
public class CuttingOrderDetail
{
public string cuttingOrderNo { get; set; }
public string reserveSalesOrderNo { get; set; }
public string itemCode { get; set; }
public string material { get; set; }
public string color { get; set; }
public string size { get; set; }
public int qty { get; set; }
public float squareFeet { get; set; }
public float squareFeetUsed { get; set; }
}
If anyone knows how to perform the linq query in lambda form or knows why LINQPad is unable to generate the lamda form it would be greatly appreciated.
This should work:
var p = CO_Leather_V.Select(l=> new CuttingOrder
{
cuttingOrderNo = "NOT SET",
reserveSalesOrderNo = "FAKE_SO_NO",
details = CO_LeatherSizeColor_V.Select(d=>new CuttingOrderDetail {cuttingOrderNo = d.OrderNo}).ToList()
}).ToList();
However, CO_LeatherSizeColor_V does not reference l, so you're going to get everything in that table, every time. You might want something like:
details = l.LeatherSizeColor.Select(d=>new CuttingOrderDetail {cuttingOrderNo = d.OrderNo}).ToList()
for that line instead.
I am developing an application in asp.net mvc and using EF code first for my data access. Here is the model I use :
public class Culture
{
[Key()]
public int CultureID { get; set; }
[Required()]
[StringLength(250)]
public string CultureName { get; set; }
[Required()]
[StringLength(250)]
public string CultureDisplay { get; set; }
public virtual List<HomePage> HomePage { get; set; }
public virtual List<Person_Local> PersonLocal { get; set; }
}
public class Person
{
public int PersonID { get; set; }
[StringLength(250)]
public string PersonPicAddress { get; set; }
public virtual List<Person_Local> PersonLocal { get; set; }
}
public class Person_Local
{
//[NotMapped()]
[Key, Column(Order = 1)]
[ForeignKey("Person")]
public int PersonID { get; set; }
[Key, Column(Order = 2)]
[ForeignKey("Culture")]
public int CultureID { get; set; }
public string PersonName { get; set; }
public string PersonFamily { get; set; }
public string PersonAbout { get; set; }
public virtual Culture Culture { get; set; }
public virtual Person Person { get; set; }
}
I dont have any problem adding new person and personlocal to db. But when I want to update the person local, as below:
public ActionResult CreatePerson([Bind(Prefix = "Person")]Person obj,
[Bind(Prefix = "Person.PersonLocal")]IEnumerable<Person_Local> plocals)
{
string photo_guid = obj.PersonPicAddress;
if (obj.PersonID != 0)
{
Person p = da.Persons.FirstOrDefault(x => x.PersonID == obj.PersonID);
TryUpdateModel(p, "Person");
if (obj.PersonLocal[0].Person.PersonID != 0)
{
int cid = obj.PersonLocal[0].Culture.CultureID;
int pid = obj.PersonLocal[0].Person.PersonID;
Person_Local ploc =
da.Person_Locals.First(x => x.CultureID == cid && x.PersonID == pid);
//update ploc
}
da.SaveChanges();
}
}
I got following error :
Multiplicity constraint violated. The role 'Person_Local_Person_Target' of the relationship 'WebApp.Models.Person_Local_Person' has multiplicity 1 or 0..1.
Edited:
I commented
TryUpdateModel(p, "Person");
And the it seems the problem has been solved ?!! Why ?!