Update sqlite database using sqlite-net in windows store app - c#

I want to update my database using linq syntax. I have updating in my sqlite database like this
var dbpath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "Users.db");
using (var db = new SQLite.SQLiteConnection(dbpath))
{
db.Update(new Booking()
{
});
db.Commit();
db.Dispose();
db.Close();
}
I want to know the update syntax syntax with simple example.Thanks

You're not even attempting to update; you're trying to insert.
Take a look here and you'll see that you can just call that instead.
var booking = db.Table<Booking>()
.Where(x => x.Name == "Jack's BBQ joint")
.FirstOrDefault();
// change something in the object
db.Update(booking);
From the docs:
/// Updates all of the columns of a table using the specified object
/// except for its primary key.
/// The object is required to have a primary key.
An alternative solution is to go lowlevel and create the queries yourself:
db.Execute("update bookings set ...");

Related

Cannot add an entity with a key that is already in use update operation

I am creating small application in which i have used LINQ To SQL to perform all operation to database.
Now here i am giving the small part of my database structure please take a look.
So update language detail i am getting the object of login using the datacontext something like this.
XVDataContext Context = new XVDataContext ();
var myQuery = from objLogIn in Context.GetTable<LogIn>() where objLogIn.Emp_Id == nEmpId select objLogIn;
In nEmpId i will always have some value.
So it is not creating any problem in fact i am getting the required record from DB and storing it in objUser object using the following code.
LogIn objUser = myQuery.First<LogIn>();
Now to update LanguageDetail i am executing following code but it throws Exception when i execute SubmitChanges line.
Here is the code that i am executing to update.
LanguageDetail obj = new LanguageDetail();
foreach (string sLanguages in TextBoxLanguagesKnown.Text.Split('\n'))
{
obj.Emp_Id = objUser.Emp_Id;
obj.Language = sLanguages.Trim();
}
objUser.LanguageDetails[0] = obj;
Context.SubmitChanges();
I already read following links.
cannot add an entity with a key that is already in use
LINQ To SQL exception with Attach(): Cannot add an entity with a key that is alredy in use
Cannot add an entity with a key that is already in use (LINQ)
By reading the above links i found that i am doing some mistake in ID fields but still i am unable to resolve.
Please tell me the clear understanding of raising this issue and how can i resolve this.
EDIT:
I simply want to update LanguageDetail table.
When i try to add new object using following code it still throws exception.
objUser.LanguageDetail.Add(obj);
You might want to add / remove languages for specific user by using following code.
var languages = TextBoxLanguagesKnown.Text.Split('\n');
// Removes deleted languages (first find all language details that are missing from the UI).
var deletedLanguages = objUser.LanguageDetails.Where(ld => !languages
.Any(l => ld.Language == l.Trim())).ToArray();
foreach(var deletedLanguage in deletedLanguages)
{
objUser.LanguageDetails.Remove(deletedLanguage);
Context.LanguageDetails.DeleteOnSubmit(deletedLanguage);
}
// Adds new languages (then adds new language details that are not found in the database).
var newLanguages = languages.Where(l => !objUser.LanguageDetails
.Any(ld => ld.Language == l.Trim())).ToArray();
foreach (string newLanguage in newLanguages)
{
var languageDetail = new LanguageDetail
{
Emp_Id = objUser.Emp_Id,
Language = newLanguage.Trim()
};
objUser.LanguageDetails.Add(languageDetail);
}
Context.SubmitChanges();
From my understanding you want to update the LanguageDetail entity in your database. In order to do so you have to do one of the following:
Retrieve the original LanguageDetail object based on its id, and update that object instead of creating a new one and assigning it the id of an existing object.
Attach the newly created object to your context instead of just giving a reference to it to your LanguageDetails collection.
The exception you are seeing happens because the way linq to sql behaves is that it threats the obj as a new object that you want to insert and because of that it tries to insert it into the language details table.
Modifying your code like that should work:
Context.LanguageDetails.Attach(obj);
objUser.Employee_LanguageDetails[0] = obj;

add list of objects to Entity database

I am new to EF. I created entity models from database.
I have tables CurrencyMaster([FromCurrency],[ToCurrency],[ActiveStatus]) and CurrencyConversion([ID],[FromCurrency],[ToCurrency],[Date],[CurrencyFactor])
I am looping for the CurrencyMaster records and accordingly DownloadCurrencyRates will get me the List<CurrencyRate> objects.
I just want to add these objects to entity database.
I tried something like this
public DownloadStatus DownloadUpdateCurrency(DateTime toDate, DateTime fromDate)
{
CurrencyEntities db = new CurrencyEntities();
var curMasters = db.CurrencyMasters.Where(x => x.ActiveStatus == 0);
foreach (var item in curMasters)
{
var curcRatesList = DownloadCurrencyRates(fromDate, toDate,
item.FromCurrency, item.ToCurrency);
//I know this is a bad code
curcRatesList.Select(x =>
{
db.AddToCurrencyConversions(
new CurrencyEntity.CurrencyConversion {
Date = x.date,
CurrencyFactor = x.value,
FromCurrency = item.FromCurrency,
ToCurrency = item.ToCurrency
}
);
return true;
});
}
db.SaveChanges();
return DownloadStatus.DownloadSuccess;
}
How can I do the same in a proper way?
Is there any way I can do this without looping for curcRatesList?
I am using .NET 3.5, and not sure about EF version.. I didn't try executing code(I need some other setup for that), but I am quite sure that what I am doing is not correct.. So I am posting here..
The procedure is correct. There is no bulk insert capability in EF that would allow to add a whole list of entities in a single method call. You must loop over the items and add them one by one.
As a side note: I would just use an ordinary foreach loop instead of that strange Select trick (which misuses the Select method, but it will work). Or - if curcRatesList is of type List<T> - you can use the Foreach method of List<T> instead of Select.

bulk delete in entity framework

I'd like to bulk delete records from a table using linq.
There's a post that describes how to do it:
Bulk-deleting in LINQ to Entities
var query = from c in ctx.Customers
where c.SalesPerson.Email == "..."
select c;
query.Delete();
But the function "Delete" doesn't exist in my var variable.
Furthermore, the function "SubmitChanges" doesn't exist on my context.
There is an interesting NuGet package that lets you do batch deletes and updates:
There is no currently supported bulk delete baked into Entity Framework. Its actually one of the features being discussed on codeplex now EF is open-source.
EntityFramework.Extended provides batch delete support (you can find this in nuget) however my experience is that it has some performance issues.
This code adds a simple extension method to any DbContext that will bulk delete all data in any table referenced within the entity framework query you provide. It works by simply extracting all table names involved in the query, and attempting to delete the data by issuing a "DELETE FROM tablename" SQL query, which is common across most types of database.
To use, simply do this:
myContext.BulkDelete(x => x.Things);
which will delete everything in the table linked to the Things entity store.
The code:
using System.Linq;
using System.Text.RegularExpressions;
namespace System.Data.Entity {
public static class DbContextExtensions {
/// <summary>
/// Efficiently deletes all data from any database tables used by the specified entity framework query.
/// </summary>
/// <typeparam name="TContext">The DbContext Type on which to perform the delete.</typeparam>
/// <typeparam name="TEntity">The Entity Type to which the query resolves.</typeparam>
/// <param name="ctx">The DbContext on which to perform the delete.</param>
/// <param name="deleteQuery">The query that references the tables you want to delete.</param>
public static void BulkDelete<TContext, TEntity>(this TContext ctx, Func<TContext, IQueryable<TEntity>> deleteQuery) where TContext : DbContext {
var findTables = new Regex(#"(?:FROM|JOIN)\s+(\[\w+\]\.\[\w+\])\s+AS");
var qry = deleteQuery(ctx).ToString();
// Get list of all tables mentioned in the query
var tables = findTables.Matches(qry).Cast<Match>().Select(m => m.Result("$1")).Distinct().ToList();
// Loop through all the tables, attempting to delete each one in turn
var max = 30;
var exception = (Exception)null;
while (tables.Any() && max-- > 0) {
// Get the next table
var table = tables.First();
try {
// Attempt the delete
ctx.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", table));
// Success, so remove table from the list
tables.Remove(table);
} catch (Exception ex) {
// Error, probably due to dependent constraint, save exception for later if needed.
exception = ex;
// Push the table to the back of the queue
tables.Remove(table);
tables.Add(table);
}
}
// Error error has occurred, and cannot be resolved by deleting in a different
// order, then rethrow the exception and give up.
if (max <= 0 && exception != null) throw exception;
}
}
}
I do it like this which seems to work fine. Please let know if there is a reason why this is bad practice in any way.
var customersToDelete = await ctx.Customers.Where(c => c.Email == "...").ToListAsync();
foreach (var customerToDelete in customersToDelete)
{
ctx.Customers.Remove(customerToDelete);
}
await ctx.SaveChangesAsync();
I was experiencing the same problem with EF executing thousands of DELETE queries after SaveChanges call. I wasn't sure that EntityFramework.Extensions commercial library would help me so I decided to implement bulk DELETE myself and came up with something similar to BG100's solution!
public async Task<List<TK>> BulkDeleteAsync(List<TK> ids)
{
if (ids.Count < 1) {
return new List<TK>();
}
// NOTE: DbContext here is a property of Repository Class
// SOURCE: https://stackoverflow.com/a/9775744
var tableName = DbContext.GetTableName<T>();
var sql = $#"
DELETE FROM {tableName}
OUTPUT Deleted.Id
// NOTE: Be aware that 'Id' column naming depends on your project conventions
WHERE Id IN({string.Join(", ", ids)});
";
return await #this.Database.SqlQuery<TK>(sql).ToListAsync();
}
If you have something like generic repository that should work for you just fine. At least you could try to fit it into your EF infrastructure.
I also tweaked it a bit more and was able to execute queries on multiple chunks of entities. It would help you if there are any restrictions of query size in your DB.
const int ChunkSize = 1024;
public async Task<List<TK>> BulkDeleteAsync(List<TK> ids)
{
if (ids.Count < 1) {
return new List<TK>();
}
// SOURCE: https://stackoverflow.com/a/20953521/11344051
var chunks = ids.Chunks(ChunkSize).Select(c => c.ToList()).ToList();
var tableName = DbContext.GetTableName<T>();
var deletedIds = new List<TK>();
foreach (var chunk in chunks) {
var sql = $#"
DELETE FROM {tableName}
OUTPUT Deleted.Id
WHERE Id IN({string.Join(", ", chunk)});
";
deletedIds.AddRange(DbContext.Database.SqlQuery<TK>(sql).ToListAsync());
}
return deletedIds;
}

"Simultaneous" insert if missing and log entry using Linq

In timing our code, I noticed that there is a substantial transaction time each time Linq communicates with SQL Server. In the past, when we used SQL directly, we could place multiple statements and send it at once. Is there a way to do this in Linq? In particular, I have two tables, a Log table and a UHAs (userhostaddress) table. If the uha is not already in the UHAs table, it must be inserted, and then the Log entry made with the uhaid. In Linq, this takes three calls, once to verify that the uha does not exist, once to insert it, and once for the log. Can I do this in one call to the database?
var uha = db.UHAs.Where(u => u.userhostaddress == _userHostAddress).FirstOrDefault();
if (uha == null)
{
var newUha = new UHA()
{
userhostaddress = _userHostAddress
};
db.UHAs.InsertOnSubmit(newUha);
db.SubmitChanges(); // 2. Second call
uha = newUha;
}
SHA1 sha1 = SHA1.Create();
var newLog= new Log()
{
requested = DateTime.UtcNow,
uhaid = uha.uhaid,
query = _query,
queryhash = sha1.ComputeHash(Encoding.UTF8.GetBytes(_query))
};
db.Log.InsertOnSubmit(newLog);
db.SubmitChanges();
Since you are using the same instance of the data context you only need to call SubmitChanges() once. That will execute all commands at once rather than making multiple trips to the sql server.

Linq update query - Is there no pretty way?

I want to update my database using a LINQ2SQL query.
However this seems for some reason to be a very ugly task compared to the otherwise lovely LINQ code.
The query needs to update two tables.
tbl_subscription
(
id int,
sub_name nvarchar(100),
sub_desc nvarchar(500),
and so on.
)
tbl_subscription2tags
(
sub_id (FK to tbl_subscription)
tag_id (FK to a table called tbl_subscription_tags)
)
Now down to my update function a send a tbl_subscription entity with the tags and everything.
I can't find a pretty way to update my database..
I can only find ugly examples where I suddenly have to map all attributes..
There most be a smart way to perform this. Please help.
C# Example if possible.
I have tried this with no effect:
public void UpdateSubscription(tbl_subscription subscription)
{
db.tbl_subscriptions.Attach(subscription);
db.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, subscription);
db.SubmitChanges(System.Data.Linq.ConflictMode.FailOnFirstConflict);
}
Source for this code is here:
http://skyeyefive.spaces.live.com/blog/cns!6B6EB6E6694659F2!516.entry
Why don't just make the changes to the objects and perform a SubmitChanges to the DataContext?
using(MyDataContext dc = new MyDataContext("ConnectionString"))
{
foreach(var foo in dc.foo2)
{
foo.prop1 = 1;
}
dc.SubmitChanges();
}
Otherwise you need to tell us more about the lifecycle of the object you want to manipulate
edit: forgot to wrap in brackets for using
Unless I'm misunderstanding your situation, I think that citronas is right.
The best and easiest way that I've found to update database items through LINQ to SQL is the following:
Obtain the item you want to change from the data context
Change whatever values you want to update
Call the SubmitChanges() method of the data context.
Sample Code
The sample code below assumes that I have a data context named DBDataContext that connects to a database that has a Products table with ID and Price parameters. Also, a productID variable contains the ID of the record you want to update.
using (var db = new DBDataContext())
{
// Step 1 - get the item from the data context
var product = db.Products.Where(p => p.ID == productID).SingleOrDefault();
if (product == null) //Error checking
{
throw new ArgumentException();
}
// Step 2 - change whatever values you want to update
product.Price = 100;
// Step 3 - submit the changes
db.SubmitChanges();
}
I found out that you can use "Attach" as seen in my question to update a table, but apparently not the sub tables. So I just used a few Attach and it worked without having to run through parameters!

Categories

Resources