Duplicate record cause no record insert - c#

Please consider this scenario:
I have two tables: Temp and Convert. The structure of these 2 tables are exactly same. I want to do some operation on each record of Temp and add it to Convert table. By doing my work, there may be duplicate records in Convert table and so I don't want to insert that record in Convert table. I wrote this code:
foreach (var item in allRecords)
{
var converted = new Convert()
{
F1 = item.F1,
F2 = item.F2,
F3 = DoWork(F3),
};
try
{
context.Convert.AddObject(converted);
context.SaveChanges();
}
catch (Exception ex)
{
var msg = "Violation of PRIMARY KEY constraint 'PK_Convert'."
+ " Cannot insert duplicate key":
if (ex.InnerException.Message.Contains(msg))
{
continue;
}
else
{
throw ex;
}
}
}
the problem is when I get exception for first duplicate and continue command executed, it seems that duplicate record not discard and still wait for save. After first exceptionÙˆ No record is stored in the database because of my first duplicate error. How I can solve this issue without checking existence of duplicate error in Convert table?
Thanks

You can try to check if the entity exists and if not - add it? Like this :
using System.Linq.Expressions;
public class ContextWithExtensionExample
{
public void DoSomeContextWork(DbContext context)
{
var uni = new Unicorn();
context.Set<Unicorn>().AddIfNotExists(uni , x => x.Name == "James");
}
}
public static class DbSetExtensions
{
public static T AddIfNotExists<T>(this DbSet<T> dbSet, T entity, Expression<Func<T, bool>> predicate = null) where T : class, new()
{
var exists = predicate != null ? dbSet.Any(predicate) : dbSet.Any();
return !exists ? dbSet.Add(entity) : null;
}
}
You can use this method directly and remember to call DbContext.SaveChanges() after the call.

var converted = new Convert()
{
F1 = item.F1,
F2 = item.F2,
F3 = DoWork(F3),
};
As F3 is your primarykey, then just check if it exists before inserting:
if(context.Convert.Any(x => x.F3 == converted.F3)
{
//deal with the error
}
else
{
context.Convert.AddObject(converted);
context.SaveChanges();
}

Related

Catch read error on EF 6

I have a DB with no constraints (given, not changeable). My model look like
public MyModel
{
public long Id { get; set; }
// Even if database column 'Value' could be NULL,
// the model - from business view - could not.
public long Value { get; set; }
}
My data I'd like to read is
Id Value
1 1
2 2
3 NULL
4 4
When I read with with DBContext.MyModel.ToList() it fails, of course. Is there any possibility to catch the error on 3rd row and return the 3 valid ones?
I don't dependent on EF but I like an automatic mapping between DB an Code.
Update:
It seems I wasn't specific enough. I need the 3 rows AS WELL AS a notification for the error.
Additional I've created a simple case for demo. In real life I have around 800 tables with up to 250 columns. I can't catch anything by model modification like dates out of range, missing relationships and other stuff.
What I really need is a try..catch for every row or an event on row reading failure, something like this.
Ok, solved. Not very elegant, but functional.
var query = _DBContext
.Database
.SqlQuery<MyModel>("SELECT * FROM MyModel");
var result = new List<MyModel>();
var enumerator = query.GetEnumerator();
while (true)
{
try
{
var success = enumerator.MoveNext();
if (!success)
break;
var model = enumerator.Current;
result.Add(model);
}
catch (Exception ex)
{
}
}
return result;
You need to use nullable type
public MyModel
{
public long Id { get; set; }
// Even if database column 'Value' could be NULL,
// the model - from business view - could not.
public long? Value { get; set; }
}
And also, in your select query, you should exlude Value = null
var myModel = models.Where(x => x.Value != null);
Hope it helps.
I'm not entirely sure I understand what you're trying to do, but if you want to get a reflection of what's in the table, then why not make your model match the query? If Value can be NULL, then make Value nullable (i.e. define it as long?).
That way, you can simply do:
var records = DbContext.MyModel.ToList();
If you then want to filter out the NULLs, you can do:
records.Where(r => r.Value.HasValue)
And if you want the ones with NULLs you can do:
records.Where(r => !r.Value.HasValue)
Or if you want to know whether any row had a NULL you could do:
records.Any(r => !r.Value.HasValue)
Use the following code:
var list = from m in DBContext.MyModel
where (m != null)
select m;
And then just convert var list to a List of your choosing.
Edit 1
var myModel = models.Where(x => x.Value != null).ToList();
As kienct89 suggested might also work.
Edit 2
There are multiple options for "catching" the error
If you want to throw an exception just use this:
if(myList.Count() < DBContext.MyModel.Count()){
Exception myException = new Exception("Not all items ware correctly loaded");
throw myException;
}
OR create a seperate array with the faulty ones:
var faultyList = from m in DBContext.MyModel
where (m == null)
select m;
Or:
var faultyList= models.Where(x => x.Value == null).ToList();

SQLite Update "Cannot update List1: it has no PK"

I'm having an issue when trying to update a value on my database and can't really find much if any help through Google.
I want to set a column called IsOpen (bool but because of SQLite I'm using integer) to 0 (false) if the EndDate for this entry is today (now). When I run my UPDATE query I get the following exception; "Cannot update List1: it has no PK".
I don't understand this because I've checked my Model class and I clearly have a PK set;
[SQLite.AutoIncrement, SQLite.PrimaryKey]
public int GoalID
{
get { return _goalID; }
set
{
if (_goalID != value)
_goalID = value;
OnPropertyChanged("GoalID");
}
}
I'm attempting to update this way;
string sql = #"UPDATE GoalsTrackerModel
SET IsOpen = '0'
WHERE EndDate = datetime('now')"; // I've also tried date('now')
_dbHelper.Update<GoalsTrackerModel>(sql);
My Update<> looks like;
public void Update<T>(string stmt) where T : new()
{
using (var conn = new SQLiteConnection(App.ConnectionString))
{
var result = conn.Query<T>(stmt);
if (result != null)
{
conn.RunInTransaction(() =>
{
conn.Update(result);
});
}
}
}
But like I said, I keep getting "Cannot update List1: it has no PK". What's throwing me off as well is if I change the WHERE to something like; WHERE IsOpen = '1' then it'll update all the values that have 1 to 0, but it'll still give me the "Cannot update List1: it has no PK" message.
Maybe my WHERE is wrong when checking if the EndDate = now? I'm implementing all this as soon as the page is opened. Any ideas?
Thanks.
"[SQLite.AutoIncrement, SQLite.PrimaryKey]" is C# code, not SQL code. Just because you've defined in C# what your primary key is, doesn't mean the SQLite table is really defined that way. You'll need to look at the table itself as it is defined within SQLite to fix that.
My Update method was causing the problem. Changed it and started using SQLiteCommand and ExecuteNonQuery instead of the SQLiteConnection's Update().
In case it helps anyone in the future, here's my new update method;
public void Update<T>(string stmt, string table) where T : new()
{
using (var conn = new SQLiteConnection(App.ConnectionString))
{
var result = conn.Query<T>("SELECT * FROM " + table);
if (result != null)
{
conn.RunInTransaction(() =>
{
SQLiteCommand cmd = conn.CreateCommand(stmt);
cmd.ExecuteNonQuery();
});
}
}
}

How to substitute table name

I need to create a "common" grid with parameters.
The problem is that in the Delete action I cannot refer to the table as a variable
I use edmx model.
public ActionResult PartialView_GridCommonDelete(System.Int64 data_autoinc)
{
var table = ViewBag.CurrentTable;
var key= ViewBag.Key;
if (data_autoinc != null)
{
try
{
//ERROR HERE
var item = **ent.table**.FirstOrDefault(it => it.product_autoinc == data_autoinc);
if (item != null)
ent.tabla.Remove(item);
ent.SaveChanges();
}
catch (Exception e)
{
ViewData["EditError"] = e.Message;
}
}
return PartialView("PartialView_GridCommon", ViewBag.CurrentSql);
}
How can I dynamically substitute the table name so as I can use it with many tables?
Thank you
What you are trying to do is not achievable by ORM i.e. defining Table at runtime.
What you can try is:
context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");
You can explicitly pass table name and fire your sql query
Give it a try.
Thanks
Nipun

Duplicate record in database when call SaveChanges()

Hi i have a problem with EF. In my application i have to load from database some content to populate a DataGrid.
UserControl :
contenus = new List<Contenu>();
contenus = sacoche.Contenus.ToList(); // i get sacoche in the parameter of the contructor
ContenuViewSource.Source = contenus;
ContenuView = (ListCollectionView)ContenuViewSource.View;
ContenuView.Refresh();
everything work just fine, but when i try to add some others Contenus i get a duplicate record in the database. The only difference between the duplicated record is that the first record loose his foreign key.
Here i add my Contenuto my Sacoche:
editableSacoche = SacocheDal.dbContext.Sacoches.Include("Contenus").First(i => i.SacocheID == editableSacoche.SacocheID);
editableSacoche.Contenus = contenus;
SacocheDal.dbContext.SaveChanges();
all i do is get the Sacoche and add to it his Contenu and finally call SaveChanges().
Here is the result :
EDIT: I tried to get only the new items but failed.
List<Contenu> contenuAjoute = contenus.Except(editableSacoche.Contenus.ToList()).ToList();
in contenuAjoutei get all the records even if they are equal ...
Try this:
editableSacoche = SacocheDal.dbContext.Sacoches.Include("Contenus").First(i => i.SacocheID == editableSacoche.SacocheID);
editableSacoche.Contenus = null;
editableSacoche.ContenusID = contenus.ID;
SacocheDal.dbContext.SaveChanges();
I found a way to achieve what i wanted. I create an ItemComparer and use Exceptto only add the new items.
Here is the comparer :
class ContenuComparer : IEqualityComparer<Contenu>
{
public bool Equals(Contenu x, Contenu y)
{
if (x.ContenuID == y.ContenuID)
return true;
return false;
}
public int GetHashCode(Contenu obj)
{
return obj.ContenuID.GetHashCode();
}
}
And Here the code :
editableSacoche = SacocheDal.dbContext.Sacoches.Include("Contenus").First(i => i.SacocheID == editableSacoche.SacocheID);
List<Contenu> contenuAjoute = contenus.Except(editableSacoche.Contenus.ToList(), new ContenuComparer()).ToList();
foreach (Contenu c in contenuAjoute)
{
editableSacoche.Contenus.Add(c);
}
SacocheDal.dbContext.SaveChanges();
I don't now if it's the right way but it works fine.

How do i check if my Linq query produced any result?

Hi guys I am using entity framework, I am facing some problem while checking if my linq returned any results, if it returns any result I want to use it as a data source, the following is the code please have a look:
var dbContext = new DBEntities();
try
{
var linQuery = from cq in dbContext.tblCharacteristics
where cq.CharacteristicID.Equals(combobox1.SelectedText)
select new
{
CharacteristicIDs = cq.CharID,
CharacteristicNames = cq.CharName
};
if (linQuery.Any()) //Also tried with linQuery.Count() != 0
{
lbChaKeyValues.DataSource = linQuery;
lbChaKeyValues.DisplayMember = "CharacteristicNames";
}
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
dbContext.Dispose();
}
I am getting following error : "DbComparisonExpression requires arguments with comparable types."
IF CharacteristicID is an integer type, the comparison won't work. Instead try
var inputFromUser = Int32.Parse( combobox1.SelectedText );
var linQuery = from cq in dbContext.tblCharacteristics
where cq.CharacteristicID == inputFromUser
select new
{
CharacteristicIDs = cq.CharID,
CharacteristicNames = cq.CharName
};
Incidentally .Any() is the correct way to test for search results. And if you're not going to use the return results, there's no need to project the data into an anonymous type. Just use select true or select cq which allows the optimizer to use the best index in the DB.

Categories

Resources