Sequence contains more than one element... in LINQ's DeleteAllOnSubmit - c#

Following examples are in C#. I am coding for Windows Phone 8.0 using Visual Studio Express 2012 for Windows Phone.
I have a simple database design (two primary tables, and one many-to-many linking table)
Ingredients(IngredientID,IngredientName)
Effects(EffectID,EffectName)
IngredientEffects(IngredientID,EffectID)
so of course to get the foreign keys working I have the standard Entities and Relationships set up in all three tables
This works fine for the following:
- Adding multiple Ingredients
- Adding multiple Effects
- Adding multiple IngredientEffects
- Deleting an Ingredient (and all of it's associated link records)
- Deleting an IngredientEffect record
- Deleting an Effect record... but only if it isn't linked to any Ingredients
When I try to delete an Effect record with multiple Ingredients linked to it, I query for all associated IngredientEffect records then do a DeleteAllOnSubmit(list); SubmitChanges();
This throws multiple "System.InvalidOperationException" with message of "Sequence contains more than one element" is being thrown in the set operation of the Ingredients.FKIngredientEffects Entity Relationship in the IngredientEffects table. I have tried to build a list of UNIQUE records from this list so I know I have no duplicate records in the list being deleted but get the same message.
I understand that this error happens with the Single type queries, but I'm not using any of those. My queries typically run like:
var query = from item in db.IngredientEffects
where item.EffectID == targetEffectID
select item;
I validate that the query is not null, then attempt to populate a list from it, and check if it is not null and has records in it before proceeding with any other work.
I am at a loss as to why I am getting this error. I use the following Entity Relationship statements in the related Table definintions:
Ingredients:
private EntityRef<IngredientEffect> _ingredientEffect;
[Association(Storage = "_ingredientEffect", ThisKey = "IngredientID", OtherKey = "IngredientID", IsUnique = false, Name = "FK_Ingredients_IngredientEffect")]
public IngredientEffect IngredientEffects
{
get { return _ingredientEffect.Entity; }
set
{
try
{
if (value != _ingredientEffect.Entity)
{
NotifyPropertyChanging("IngredientEffects");
_ingredientEffect.Entity = value;
NotifyPropertyChanged("IngredientEffects");
}
}
catch (Exception exc)
{
Debug.WriteLineIf(Debugger.IsAttached, "AlchemistDB.Ingredients.FKIngredientEffects(set) Exception: " + exc.Message);
//throw new Exception("AlchemistDB.Ingredient.FKIngredientEffects(set) failed.", exc);
}
}
}
Effects:
private EntityRef<IngredientEffect> _effectIngredients;
[Association(Storage = "_effectIngredients", ThisKey = "EffectID", OtherKey = "EffectID", IsUnique = false, Name = "FK_Effect_IngredientEffect")]
public IngredientEffect EffectIngredients
{
get { return _effectIngredients.Entity; }
set
{
try
{
NotifyPropertyChanging("EffectIngredients");
_effectIngredients.Entity = value;
NotifyPropertyChanged("EffectIngredients");
}
catch (Exception exc)
{
Debug.WriteLineIf(Debugger.IsAttached, "AlchemistDB.Effect.FKEffectIngredients(set) Exception: " + exc.Message);
//throw new Exception("AlchemistDB.Effect.FKEffectIngredients(set) failed.", exc);
}
}
}
IngredientEffects:
private EntityRef<Ingredient> _ingredients;
[Association(Storage = "_ingredients", ThisKey = "IngredientID", OtherKey = "IngredientID", IsUnique = false, IsForeignKey = true, Name = "FK_Ingredients_IngredientEffect")]
public Ingredient Ingredients
{
get { return this._ingredients.Entity; }
set
{
try
{
if (value != _ingredients.Entity)
{
NotifyPropertyChanging("Ingredients");
this._ingredients.Entity = value;
NotifyPropertyChanged("Ingredients");
}
}
catch (Exception e)
{
Debug.WriteLineIf(Debugger.IsAttached, "AlchemistDB.IngredientEffect.FKIngredients(set) exception:" + e.Message);
throw new Exception("AlchemistDB.IngredientEffect.FKIngredients(set) failed.", e);
}
}
}
private EntityRef<Effect> _effects;
[Association(Storage = "_effects", ThisKey = "EffectID", OtherKey = "EffectID", IsUnique = false, IsForeignKey = true, Name = "FK_Effect_IngredientEffect")]
public Effect Effects
{
get { return this._effects.Entity; }
set
{
try
{
if (value != _effects.Entity)
{
NotifyPropertyChanging("Effects");
this._effects.Entity = value;
NotifyPropertyChanged("Efffects");
}
}
catch (Exception e)
{
Debug.WriteLineIf(Debugger.IsAttached, "AlchemistDB.IngredientEffect.FKEffects(set) exception:" + e.Message);
throw new Exception("AlchemistDB.IngredientEffect.FKEffects(set) failed.", e);
}
}
}
Any assistance provided will be most welcome!
Thanks,
-Mark

If any Foreign Key's set declaration in a many-to-many Table has conditional logic (like:
if (value!=_myprivateproperty)
{
NotifyPropertyChanging("MyPublicPropertyName");
_myprivateproperty = value;
NotifyPropertyChanged("MyPublicPropertyName");
}
it will cause LINQ to throw this exception, each time a record in that table is deleted. Get rid of the conditional and just use:
NotifyPropertyChanging("MyPublicPropertyName");
_myprivateproperty = value;
NotifyPropertyChanged("MyPublicPropertyName");
Still not sure WHY this happens, but to me it appears to be a bug in LINQ-to-SQL itself.

Related

GET<TModel> NOT by primaryKEY

I am using this function to query a table by its primary ID.
public virtual List<TModel> LoadAllWithChildren()
{
lock(Connection)
{
var result = LoadAll();
foreach (var item in result)
{
try
{
Connection.GetChildren(item);
}
catch (Exception e)
{
DebugTraceListener.Instance.WriteLine(GetType().Name,
"Can not load Child for itemType: " + item.GetType().Name + " reason: " + e);
}
}
return result;
}
}
But this always return results in regards to the primary key. The table I am querying on looks like this:
So when I do this, I get all entries in this table (not just the ones you see in the picture, those are the ones that I want)
So I did a small workaround:
var persistance = await Task.Run(() => PersistenceService.PresentationSequence.LoadAllWithChildren());
List<PresentationSequence> resSequence = new List<PresentationSequence>();
foreach(var elem in persistance)
if (elem.PresentationId == 166)
resSequence.Add(elem);
The result is the list as seen in the picture.
This, however, is slow.
Is there a way to use another SQlite function that will give me the list already filter for "166" in "presentationID"?
(So no local work is done)
EDIT: I have tried using this function:
public virtual TModel LoadById(int id)
{
lock(Connection)
{
try
{
var result = Connection.Get<TModel>(id);
return result;
}
catch (Exception ex)
{
DebugTraceListener.Instance.WriteLine(GetType().Name, $"Cannot find item with ID: {id}\n\n{ex}");
return null;
}
}
}
But this will only take the primary key in. But I want to query for presentation ID and not get a single result from the ID column
I ended up going with the query function:
try
{
var result = Connection.Query<TModel>(querystring);
return result;
}

System.Data.Entity.Validation.DbEntityValidationException

I have a project that uses Entity Framework. While calling SaveChanges on my DbEntityValidationException, I get the following exception:
System.Data.Entity.Validation.DbEntityValidationException: 'Validation
failed for one or more entities. See 'EntityValidationErrors' property
for more details.'
This is all fine and dandy, but I don't want to attach a debugger every time this exception occurs. More over, in production environments I cannot easily attach a debugger so I have to go to great lengths to reproduce these errors.
How can I see the details hidden within the DbEntityValidationException?
private void btnCreateLetter_Click(object sender, EventArgs e)
{
using (TransactionScope TS = new TransactionScope())
{
try
{
Letter TblLetter = new Letter();
TblLetter.Subject = txtSubject.Text.Trim();
TblLetter.Abstract = txtAbstract.Text.Trim();
TblLetter.Body = ckeCKEditor.TextEditor.Text.Trim();
{
var LastLetterID = (from Letter in Database.Letters orderby Letter.LetterID descending select Letter).First();
TblLetter.LetterNO = PublicVariable.TodayDate.Substring(0, 4).Substring(2, 2) + PublicVariable.gDetermineJobLevel + "/" + (LastLetterID.LetterID + 1);
}
TblLetter.CreateDate = lblCreateDate.Text;
TblLetter.UserID = PublicVariable.gUserID;
if (rdbClassification.Checked == true)
{
TblLetter.SecurityType = 1;
}
else if (rdbConfidential.Checked == true)
{
TblLetter.SecurityType = 2;
}
else if (rdbSeries.Checked == true)
{
TblLetter.SecurityType = 3;
}
if (rdbActionType.Checked == true)
{
TblLetter.UrgencyType = 1;
}
else if (rdbInstantaneous.Checked == true)
{
TblLetter.UrgencyType = 2;
}
else if (rdbAnnie.Checked == true)
{
TblLetter.UrgencyType = 3;
}
TblLetter.ArchivesType = 1;
if (rdbFollowHas.Checked == true)
{
TblLetter.FollowType = 1;
}
else if (rdbFollowHasnoot.Checked == true)
{
TblLetter.FollowType = 2;
}
if (rdbAttachmentHas.Checked == true)
{
TblLetter.AttachmentType = 1;
}
else if (rdbAttachmentHasnot.Checked == true)
{
TblLetter.AttachmentType = 2;
}
TblLetter.ReadType = 1;
TblLetter.LetterType = 1;
TblLetter.DraftType = 1;
if (rdbResponseDeadlineHas.Checked == true)
{
TblLetter.AnswerType = 1;
TblLetter.AnswerReadLine = String.Format("{0:yyyy/MM/dd}", Convert.ToDateTime(pdpSetResponseDeadline.Value.Year.ToString() +
"/" + pdpSetResponseDeadline.Value.Month.ToString() + "/" + pdpSetResponseDeadline.Value.Day.ToString()));
}
else if (rdbResponseDeadlineHasnot.Checked == true)
{
TblLetter.AnswerType = 2;
}
Database.Letters.Add(TblLetter);
Database.SaveChanges();
if (rdbAttachmentHas.Checked == true)
{
if (lblPath.Text != "")
{
FileStream ObjectFileStream = new FileStream(lblPath.Text, FileMode.Open, FileAccess.Read);
int Lenght = Convert.ToInt32(ObjectFileStream.Length);
byte[] ObjectData;
ObjectData = new byte[Lenght];
string[] strPath = lblPath.Text.Split(Convert.ToChar(#"\"));
ObjectFileStream.Read(ObjectData, 0, Lenght);
ObjectFileStream.Close();
AttachFile TableAttachFile = new AttachFile();
TableAttachFile.FileSize = Lenght / 1024;
TableAttachFile.FileName = strPath[strPath.Length - 1];
TableAttachFile.FileData = ObjectData;
TableAttachFile.LetterID = TblLetter.LetterID;
Database.AttachFiles.Add(TableAttachFile);
Database.SaveChanges();
}
}
TS.Complete();
MessageBox.Show("saved", "ok", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (InvalidCastException ex)
{
MessageBox.Show(ex.ToString());
MessageBoxIcon.Error);
return;
}
}
}
You have to get the validation errors from the db.SaveChanges() method of the DatabaseContext object -- you can't get them where you are.
You can either modify the SaveChanges() method of your database context and wrap it in a try-catch block, or (since the class is partial) you can extend the partial class within your application and just override the SaveChanges() method.
There is a nice blog post about this called Easy way to improve DbEntityValidationException of Entity Framework here.
The essence of it is something like this:
public partial class NorthwindEntities
{
public override int SaveChanges()
{
try
{
return base.SaveChanges();
}
catch (DbEntityValidationException ex)
{
// Retrieve the error messages as a list of strings.
var errorMessages = ex.EntityValidationErrors
.SelectMany(x => x.ValidationErrors)
.Select(x => x.ErrorMessage);
// Join the list to a single string.
var fullErrorMessage = string.Join("; ", errorMessages);
// Combine the original exception message with the new one.
var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);
// Throw a new DbEntityValidationException with the improved exception message.
throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
}
}
}
The blogger explains:
That’s it! The rest of your code will automatically use the overridden
SaveChanges so you don’t have to change anything else. From now on,
your exceptions will look like this:
System.Data.Entity.Validation.DbEntityValidationException: Validation
failed for one or more entities. See 'EntityValidationErrors' property
for more details. The validation errors are: The field PhoneNumber
must be a string or array type with a maximum length of '12'; The
LastName field is required.
The DbEntityValidationException also contains the entities that caused
the validation errors. So if you require even more information, you
can change the above code to output information about these entities.
As mention, you need to check on your EntityValidationError when it throws the exception.
You should fix that validation error, instead of asking bypass this exception.
Normally these errors are table allow length, data type, column does not allow null and etc. There will be exact fiend name mention in your exception too.

Iterating thru the list and updating data can't find the item in the db

I have a list in a view with values that need to be updated.
When calling the http method, I am going thru the list components and looking into the database for a item with the right Id and updating the Grade value. My problem is that I can't return the right item from the database, it always returns null. I have checked with debugging, the item from the list with the Id that I am looking for has the right value, but I can't return the item from db.
I have also tried with the sql raw query and it gives me the same error.
This is my code - the var exam is always null :
public ActionResult UpdateExams(ExamsList examList)
{
var examVM = new ExamViewModel
{
Professor = _context.Professor.ToList()
};
examVM.ExamsList = examList;
if (!ModelState.IsValid)
{
var GradesList = new List<int>();
for (int i = 5; i <= 10; i++)
{
GradesList.Add(i);
}
var GradesListSL = new SelectList(GradesList);
return PartialView("ExamsTable", examList);
}
try
{
for (int i = 0; i < examList.ExamDetails.Count; i++)
{
var exam = _context.Exam.Single(e => e.Id == examList.ExamDetails[i].Id);
// var exam = _context.Database.SqlQuery<Exam>(#"SELECT Id as Id,Grade as Grade
//FROM Exam
//WHERE Id={0})
//", examList.ExamDetails[i].Id).ToList();
exam.Grade = examList.ExamDetails[i].Grade == 0 ? exam.Grade : examList.ExamDetails[i].Grade;
}
// _context.SaveChanges();
TempData["InsertingExam"] = "Success!";
// return RedirectToAction("Create", "Exams");
return Json(new { redirectTo = Url.Action("Edit", "Exams") });
}
catch (System.Data.Entity.Infrastructure.DbUpdateException ex) //DbContext
{
string exception = ex.StackTrace + ex.Message;
ModelState.AddModelError("Error", exception);
return View(examVM);
throw;
}
catch (Exception ex)
{
string exception = ex.StackTrace + ex.Message;
ModelState.AddModelError("Error", exception);
return View(examVM);
throw;
}
finally
{
_context.SaveChanges();
}
}
The problem was that I was trying to do the database operation with the view model class.
After I added creating the model class from the view model everything worked just fine.

Cant retrieve guid from dropdown

I am trying to save a guid to a database from a populated dropdown.
The data in the class is fine but when i save the guid back to the database for reference i get the error: "guid is not in recognized format".
When i look at the value attribtute it is empty
I am using the following to standardize my lookups
/// <summary>
/// Gets the days of week.
/// </summary>
/// <returns></returns>
public List<StandardLookup> GetStandardLookups(Guid lookkupCode)
{
List<StandardLookup> lookups = new List<StandardLookup>();
try
{
var q = from lookup in fhsNetEntities.fhsLookUps.Where(a => a.lookup_type == lookkupCode).OrderByDescending(o => o.colOrder)
orderby lookup.lookup_description
select new
{
LookLookupValue = lookup.lookup,
LookupDescription = lookup.lookup_Code.Trim(),
Order = lookup.colOrder
};
if (q != null)
{
Array.ForEach(q.ToArray(), l =>
{
lookups.Add(new StandardLookup(l.LookLookupValue, l.LookupDescription, l.Order));
});
}
}
catch (Exception ex)
{
string inner = string.Empty;
if (ex.InnerException != null)
{
inner = ex.InnerException.ToString();
}
logger.Error("Error in GetDaysOfWeek function aperturenetdal " + ex.ToString() + " " + inner);
return null;
}
return lookups;
}
rdSaluation.DataSource = rdSaluations;
rdSaluation.DataValueField = "LookupValue";
rdSaluation.DataTextField = "LookupDescription";
rdSaluation.DataBind();
But when i got to my save event and debug I am getting the following error
And here you can see its grabbing the name value instead by mistake.
Put the whole code on Page_Load inside !IsPostBack. You are re-initializing your _fhsPersonal otherwise. Also you are using a variable by the same name in your btn_Click event. Change that too.

Error adding multiple records MVC

i'm trying to add multiple textbox values to database it is working on just single textbox row but now working when i'm adding multiple rows of textboxes. i'm sharing what i have done so far.
Action Method:
public async Task<ActionResult> Create(FormCollection values)
{
var customer = new Customer();
var model = new TicketViewModel();
TryUpdateModel(model.TicketDetail);
try
{
foreach (var ticket in model.Tickets)
{
ticket.Date = DateTime.Now;
ticket.ProcessId = DateTime.Now.Ticks.ToString().Substring(12, 6);
ticket.CreationMethod = "Manual";
ticket.isCustomer = User.IsInRole("Customer") ? true : false;
ticket.Total = 0;
ticket.Email = model.TicketDetail.Ticket.Email;
customer.City = "Not Specified";
customer.Country = "Not SPecified";
customer.Image = "~/Images/nopic.jpg";
customer.Password = System.Web.Security.Membership.GeneratePassword(11, 3);
customer.IsActive = true;
customer.CreationMethod = "Manual";
customer.DateAdded = DateTime.Now;
customer.Email = ticket.Email;
customer.FirstMidName = string.IsNullOrEmpty(ticket.FullName) ? "Not Specified" : ticket.FullName;
customer.LastName = "Not Specified";
customer.Salutation = "Not Specified";
customer.UserName = DateTime.Now.Ticks.ToString().Substring(3, 9);
//ticket detail
var abcd = values["abcd"].ToString();
var getID = await db.Parts.Where(c => c.PartNumber == abcd)
.FirstOrDefaultAsync();
model.TicketDetail.GenericOrderId = ticket.GenericOrderId;
model.TicketDetail.PersonID = customer.PersonID;
model.TicketDetail.Status = "New";
model.TicketDetail.PartId = getID.PartId;
model.TicketDetail.Ticket.Date = DateTime.Now;
}
try
{
// db.Tickets.Add(ticket);
db.Customers.Add(customer);
db.TicketDetails.Add(model.TicketDetail);
}
catch (Exception ex)
{
ViewBag.PartId = new SelectList(db.Parts.Take(5), "PartId", "Name");
ModelState.AddModelError("", string.Format(ex.Message + "\n" + ex.InnerException));
return View(model.TicketDetail);
}
// Save all changes
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
catch(Exception ex)
{
ModelState.AddModelError("", String.Format(ex.Message + "\n" + ex.InnerException));
//Invalid - redisplay with errors
return View(model.TicketDetail);
}
}
ViewModel:
public class TicketViewModel
{
public TicketViewModel()
{
TicketDetails = new List<TicketDetail>();
TicketDetail = new TicketDetail();
Ticket = new Ticket();
Tickets = new List<Ticket>();
}
public virtual Ticket Ticket { get; set; }
public virtual IEnumerable<Ticket> Tickets { get; set; }
public virtual TicketDetail TicketDetail { get; set; }
public virtual IEnumerable<TicketDetail> TicketDetails { get; set; }
}
it is also giving error on this "TryUpdateModel(model.TicketDetail);" the error is value cannot be null, please guide me i'm stuck here i have searched internet but couldn't found any appropriate solution. i want to add multiple records
First all properties of your TicketViewModel class have to be instantiated.
To add multiple records (multiple Insert) you could use a StringBuilder and append the insert statements to it. You then have one big query string to be executed on your database.
If using values this is also a valid way:
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);
And loading the data to be inserted directly from a file is even faster.
Edit
(after down voting for no reason)
Because some people act like they know it all:
SQL injections are indeed a serious problem when dealing with Database access. That's no secret at all. A common technique to prevent the SQL query from being 'highjacked' you simply use the SQLCommand.Parameters property which is used to map each value individually to the statement to separate the query statement from the data (values) this way. It's now impossible to inject or manipulate statements whithout breaking them. And server side validation is standard to obtain maximum security as well as escaping special input characters and avoiding the use of privilegs with no or low restrictions.
This is NOT a wrong answer.

Categories