To delete all the rows in a table, I am currently doing the following:
context.Entities.DeleteAllOnSubmit(context.Entities);
context.SubmitChanges();
However, this seems to be taking ages. Is there a faster way?
You could do a normal SQL truncate or delete command, using the DataContext.ExecuteCommand method:
context.ExecuteCommand("DELETE FROM Entity");
Or
context.ExecuteCommand("TRUNCATE TABLE Entity");
The way you are deleting is taking long because Linq to SQL generates a DELETE statement for each entity, there are other type-safe approaches to do batch deletes/updates, check the following articles:
Batch Updates and Deletes with LINQ to SQL
LINQ to SQL Extension: Batch Deletion with Lambda Expression
Unfortunately LINQ-to-SQL doesn't execute set based queries very well.
You would assume that
context.Entities.DeleteAllOnSubmit(context.Entities);
context.SubmitChanges();
will translate to something like
DELETE FROM [Entities]
but unfortunately it's more like
DELETE FROM [dbo].[Entities] WHERE ([EntitiesId] = #p0) AND ([Column1] = #p1) ...
DELETE FROM [dbo].[Entities] WHERE ([EntitiesId] = #p0) AND ([Column1] = #p1) ...
DELETE FROM [dbo].[Entities] WHERE ([EntitiesId] = #p0) AND ([Column1] = #p1) ...
You'll find the same when you try to do bulk update in LINQ-to-SQL. Any more than a few hundred rows at a time and it's simply going to be too slow.
If you need to do batch operations & you're using LINQ-to-SQL, you need to write stored procedures.
I like using an Extension Method, per the following:
public static class LinqExtension
{
public static void Truncate<TEntity>(this Table<TEntity> table) where TEntity : class
{
var rowType = table.GetType().GetGenericArguments()[0];
var tableName = table.Context.Mapping.GetTable(rowType).TableName;
var sqlCommand = String.Format("TRUNCATE TABLE {0}", tableName);
table.Context.ExecuteCommand(sqlCommand);
}
}
you could also use this:
Public void BorraFilasTabla()
{
using(basededatos db = new basededatos())
{
var ListaParaBorrar = db.Tabla.Tolist();
db.Tabla.RemoveRange(ListaParaBorrar);
}
}
The Below c# code is used to Insert/Update/Delete/DeleteAll on a database table using LINQ to SQL
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace PracticeApp
{
class PracticeApp
{
public void InsertRecord(string Name, string Dept) {
LinqToSQLDataContext LTDT = new LinqToSQLDataContext();
LINQTOSQL0 L0 = new LINQTOSQL0 { NAME = Name, DEPARTMENT = Dept };
LTDT.LINQTOSQL0s.InsertOnSubmit(L0);
LTDT.SubmitChanges();
}
public void UpdateRecord(int ID, string Name, string Dept)
{
LinqToSQLDataContext LTDT = new LinqToSQLDataContext();
LINQTOSQL0 L0 = (from item in LTDT.LINQTOSQL0s where item.ID == ID select item).FirstOrDefault();
L0.NAME = Name;
L0.DEPARTMENT = Dept;
LTDT.SubmitChanges();
}
public void DeleteRecord(int ID)
{
LinqToSQLDataContext LTDT = new LinqToSQLDataContext();
LINQTOSQL0 L0;
if (ID != 0)
{
L0 = (from item in LTDT.LINQTOSQL0s where item.ID == ID select item).FirstOrDefault();
LTDT.LINQTOSQL0s.DeleteOnSubmit(L0);
}
else
{
IEnumerable<LINQTOSQL0> Data = from item in LTDT.LINQTOSQL0s where item.ID !=0 select item;
LTDT.LINQTOSQL0s.DeleteAllOnSubmit(Data);
}
LTDT.SubmitChanges();
}
static void Main(string[] args) {
Console.Write("* Enter Comma Separated Values to Insert Records\n* To Delete a Record Enter 'Delete' or To Update the Record Enter 'Update' Then Enter the Values\n* Dont Pass ID While Inserting Record.\n* To Delete All Records Pass 0 as Parameter for Delete.\n");
var message = "Successfully Completed";
try
{
PracticeApp pa = new PracticeApp();
var enteredValue = Console.ReadLine();
if (Regex.Split(enteredValue, ",")[0] == "Delete")
{
Console.Write("Delete Operation in Progress...\n");
pa.DeleteRecord(Int32.Parse(Regex.Split(enteredValue, ",")[1]));
}
else if (Regex.Split(enteredValue, ",")[0] == "Update")
{
Console.Write("Update Operation in Progress...\n");
pa.UpdateRecord(Int32.Parse(Regex.Split(enteredValue, ",")[1]), Regex.Split(enteredValue, ",")[2], Regex.Split(enteredValue, ",")[3]);
}
else
{
Console.Write("Insert Operation in Progress...\n");
pa.InsertRecord(Regex.Split(enteredValue, ",")[0], Regex.Split(enteredValue, ",")[1]);
}
}
catch (Exception ex)
{
message = ex.ToString();
}
Console.Write(message);
Console.ReadLine();
}
}
}
Related
I can't find anything specific in the Firebird.NET documentaion, but I need to extract multiple specific data rows out of a table from my Firebird database. I later want to host the server and website formulars, where you can list all the employee with it's specific data fields which i want to choose manually.
The sql query would be:
SELECT employee_id, name, first_name, active_or_not
FROM t_personal
I can already make a query with a single return string inside the server-class using Dapper like this:
using System;
using System.Linq;
using FirebirdSql.Data.FirebirdClient;
using Dapper;
using System.Data;
//the references i use
public string SingleQuery(string commando)
{
try
{
String query = _festeVerbindung.Query<String>(commando).Single();
return query;
}
catch (Exception oof)
{
return oof.Message;
}
}
Preferably i would like to extract them into a string array because i think this would be the best option to put it in an output web formular later, but if you have any better ideas i would appreciate it.
I don't think your query will work as you expect. You are returning one row of type string, but your SQL query is returning multiple fields. If you really want to return a string, then in the SQL statement you can concatenate the fields. But this would make dealing with the individual fields in the C# code harder. I would suggest something along the lines of below. I am illustrating 3 ways to do this. 1) with no where clause in the SQL, then another with a where clause and lastly converting the results to an array or strings. The snippet for the last i wouldn't recommend it, it is sloppy but it is there to show how you can transform the return set into an array of strings. If you need to really return an array of strings i would suggest using a CSV or JSON test serializer. Those packages call handle the anomalies you'd find when dealing with strings (like NULL or embedded commas, etc. ).
-HTH
public class EmployeeRec
{
public int Employee_Id { get; set; }
public string Name { get; set; }
public string First_name { get; set; }
public string active_or_not { get; set; }
}
public class QueryClass
{
public EmployeeRec[] ExecuteQueryNoWhereClause()
{
var sql = #"SELECT employee_id, name, first_name, active_or_not FROM t_personal";
try
{
using (IDbConnection _festeVerbindung = Data.Connection.GetConnection("My Connectionstring"))
{
var results = _festeVerbindung.Query<EmployeeRec>(sql).ToArray();
var activeOnly = results.Where(x => x.active_or_not == "Y");
return results;
}
}
catch (Exception oof)
{
throw;
}
}
public EmployeeRec[] ExecuteQueryWithWhereClause(string activeFlag)
{
var sql = #"SELECT employee_id, name, first_name, active_or_not FROM t_personal WHere active_or_not = #ACTIVE_FLAG";
try
{
using (IDbConnection _festeVerbindung = Data.Connection.GetConnection("My Connectionstring"))
{
var results = _festeVerbindung.Query<EmployeeRec>(sql, new { ACTIVE_FLAG = activeFlag }).ToArray();
foreach (var item in results)
{
}
return results;
}
}
catch (Exception oof)
{
throw;
}
}
public string[] ExecuteQueryReturnStringArray(string activeFlag)
{
StringBuilder sb = new StringBuilder();
List<string> retArray = new List<string>();
var sql = #"SELECT employee_id, name, first_name, active_or_not FROM t_personal WHere active_or_not = #ACTIVE_FLAG";
try
{
using (IDbConnection _festeVerbindung = Data.Connection.GetConnection("My Connectionstring"))
{
var results = _festeVerbindung.Query<EmployeeRec>(sql, new { ACTIVE_FLAG = activeFlag }).ToArray();
/*
*
* There are better ways to do this, if you need to return a string array you should a Json or CSV text serializer like Servicestack.Text *
*
*/
retArray.Add("employee_id, name, first_name, active_or_not");
foreach (var item in results)
{
retArray.Add(item.Employee_Id.ToString() + "," + item.Name + "," + item.First_name + "," + item.active_or_not);
}
return retArray.ToArray();
}
}
catch (Exception oof)
{
throw;
}
}
}
I have number of records that I have loaded from database and I want to update set couple values before I return them. The only main requirement I do not want multiple commands updating each record one by one.
Please note my ids are GUIDs(uniqueidentifier)
so far I have my code as
public IEnumerable<Person> GetUnprocessedPeople(int batchSize)
{
List<Queue_ImportQueue> list;
using (IDbConnection db = OpenedConnection)
{
string peopleList = $"SELECT TOP({batchSize}) * FROM [dbo].[Person]";
list = db.Query<Person>(peopleList).ToList();
using (IDbTransaction transactionScope = db.BeginTransaction(IsolationLevel.Serializable))
{
string updateQuery = $"UPDATE [dbo].[Person] SET Created = GETDATE() WHERE Id ='#ids'";
try
{
db.Execute(updateQuery, new { Id = list.Select(x => x.Id) }, transactionScope);
transactionScope.Commit();
}
catch (Exception ex)
{
transactionScope.Rollback();
throw;
}
}
}
return list;
}
OK the solution was quite simple.
There is no need for specific casting.
just ensure you have all arguments correct.
So extract that has fixed the query for me:
string updateQuery = $"UPDATE [dbo].[Person] SET Created = GETDATE() WHERE Id ='#Ids'";
...
db.Execute(updateQuery, new { Ids = list.Select(x => x.Id) }, transactionScope);
I have a class Announcement, and I have a list of id, I am using the nuget package: sqlite-net-pcl.
How can I delete an announcement from my Announcement table if I have it id. I am trynig to use linq like: await connection.DeleteAsync(announcement).Where(...)
but I can't use Where with the DeleteAsync, so I tried
var query = connection.Table<Announcement>().Where(announcement=>announcement.AnnouncementId == announcementId)
it gives me this erro :System.NotSupportedException: Cannot delete AsyncTableQuery`1: it has no PK
I think you are looking for something like this:
public static int Delete(string url)
{
using (var databaseManager = DatabaseManager.Instance)
{
lock (databaseManager)
{
return databaseManager.Database.Table<File>().Delete(x => x.Url == url);
}
}
}
This is using SQLite;
https://developer.xamarin.com/guides/android/data-and-cloud-services/data-access/part-3-using-sqlite-orm/
I have never used the nuget in question but I have had a quick look on the source and it would appear that TableQuery has a sync method called Delete that returns an integer.
The code you have included above is returning an object of type TableQuery<Announcement>. The class TableQuery contains the following definition:
public int Delete(Expression<Func<T, bool>> predExpr)
{
if (predExpr.NodeType == ExpressionType.Lambda) {
var lambda = (LambdaExpression)predExpr;
var pred = lambda.Body;
var args = new List<object> ();
var w = CompileExpr (pred, args);
var cmdText = "delete from \"" + Table.TableName + "\"";
cmdText += " where " + w.CommandText;
var command = Connection.CreateCommand (cmdText, args.ToArray ());
int result = command.ExecuteNonQuery();
return result;
} else {
throw new NotSupportedException ("Must be a predicate");
}
}
It would seem that you should just use the following:
connection.Table<Announcement>().Delete(announcement=>announcement.AnnouncementId == announcementId)
This code is completely untested and is from reviewing the source code of the nuget package on Github (https://github.com/praeclarum/sqlite-net/blob/master/src/SQLite.cs).
Have your ID Property the Primary Key Attribute ?
[PrimaryKey,AutoIncrement]
public int Id { get; set; }
I am looking for ways to do LINQ on a table selected in runtime via string variable.
This is what I have so far using reflection:
private Entities ctx = new Entities();
public List<AtsPlatform> GetAtsPlatformByName(string atsPlatformName)
{
List<AtsPlatform> atsPlatform = null;
System.Reflection.PropertyInfo propertyInfo = ctx.GetType().GetProperty(atsPlatformName.ToLower());
var platform = propertyInfo.GetValue(ctx, null);
// it fails here highlighting "platform" with error that reads "Error 1 Could not find an implementation of the query pattern for source type 'System.Data.Objects.ObjectQuery'. 'Select' not found. Consider explicitly specifying the type of the range variable 'ats'."
atsPlatform = ((from ats in platform select new AtsPlatform { RequestNumber = ats.RequestNumber, NumberOfFail = ats.NumberOfFail, NumberOfFailWithCR = ats.NumberOfFailWithCR, NumberOfTestCase = ats.NumberOfTestCase }).ToList());
return atsPlatform;
}
In my model class, I have:
public class AtsPlatform
{
public string Name { get; set; }
public string RequestNumber { get; set; }
public Int32? NumberOfFail { get; set; }
public Int32? NumberOfTestCase { get; set; }
public Int32? NumberOfFailWithCR { get; set; }
}
In Database, I have the following tables: "ats1", "ats2", "ats3" .. "atsN" where each of them has the same entity fields as the properties defined in "AtsPlatform"
What I would like to do is simply:
List<AtsPlatform> a1 = GetAtsPlatformByName("ats1");
List<AtsPlatform> a2 = GetAtsPlatformByName("ats2");
List<AtsPlatform> aN = GetAtsPlatformByName("atsN");
I could use "switch" but this makes the code less expandable and requires update whenever new "ats(N+1)" gets created.
My 2 days of research lead me nowhere but back to ground zero. I'm quite stuck.
PLEASE HELP! Thanks!
Instead of reflection, how about using the SqlQuery function?
So
List<AtsPlatform> GetAtsPlatformByName(int index)
{
using (var ctx = new Entities())
{
return ctx.Database.SqlQuery<AtsPlatform>("SELECT * FROM dbo.ats" + index)
.ToList();
}
}
Also, there is no change tracking on the entities using the SqlQuery method on the Database object (which is ok in your case I suppose since the AtsPlatform class only contains primitive properties).
For changes tracking you will need to use the DbSet SqlQuery method, and may need to mix some reflection in.
Sorry for my late response as I wondered off trying out different solutions:
Solution #1: Master Table
As suggested by #Alexw, creating a Master Table works the best ONLY if you are allowed to change the design of the db. I'm currently working with the db owner to make this change. Due to dependencies, this change has to wait till next phase.
Meanwhile, I've created mock db to exercise this approach.
Solution #2: Raw Query
As Suggested by #Umair, raw query will do the job. I've created a class that handles raw sql query.
public class AtsRawQuery
{
private string ConnetionString = "";
public AtsRawQuery(string connectionString)
{
this.ConnetionString = connectionString;
}
public List<List<string>> Query(string queryString)
{
List<List<string>> results = null;
MySqlConnection conn = null;
MySqlDataReader rdr = null;
try
{
conn = new MySqlConnection(this.ConnetionString);
conn.Open();
MySqlCommand cmd = new MySqlCommand(queryString, conn);
rdr = cmd.ExecuteReader();
if (rdr.HasRows)
{
results = new List<List<string>>();
while (rdr.Read())
{
List<string> curr_result = new List<string>();
for (int columnIndex = 0; columnIndex <= rdr.FieldCount - 1; columnIndex++)
{
curr_result.Add(rdr.GetString(columnIndex));
}
results.Add(curr_result);
}
}
}
catch (MySqlException ex)
{
Console.WriteLine(ex.Message);
return null;
}
finally
{
if (rdr != null)
{
rdr.Close();
}
if (conn != null)
{
conn.Close();
}
}
return results;
}
}
This class returns a 2 dimension list for later consumption.
In my model class, I added a parser method:
public class AtsPlatform
{
public string Name { get; set; }
public string RequestNumber { get; set; }
public Int32? NumberOfFail { get; set; }
public Int32? NumberOfTestCase { get; set; }
public Int32? NumberOfFailWithCR { get; set; }
public void Parse(string name, string requestNumber, string numberOfFail, string numberOfTestCase, string numberOfFailWithCR)
{
Int32 temp;
this.Name = name;
this.RequestNumber = requestNumber;
this.NumberOfFail = (Int32.TryParse(numberOfFail, out temp)) ? Int32.Parse(numberOfFail) : 0;
this.NumberOfTestCase = (Int32.TryParse(numberOfTestCase, out temp)) ? Int32.Parse(numberOfTestCase) : 0;
this.NumberOfFailWithCR = (Int32.TryParse(numberOfFailWithCR, out temp)) ? Int32.Parse(numberOfFailWithCR) : 0;
}
}
Solution #2(b): Raw Query using ExecuteStoreCommand
public List<AtsPlatform> GetAtsPlatformByName(string atsPlatformName)
{
List<AtsPlatform> atsPlatforms = null;
string stm = String.Format("SELECT RequestNumber, NumberOfFail, NumberOfTestCase, NumberOfFailWithCR FROM {0}", atsPlatformName);
atsPlatforms = new List<AtsPlatform>();
foreach (AtsPlatform ats in ctx.ExecuteStoreQuery<AtsPlatform>(stm))
{
atsPlatforms.Add(ats);
}
return atsPlatforms;
}
Solution #3: Stored Procedure
I've created a stored procedure and here is the code:
DELIMITER $$
CREATE PROCEDURE `UnionAtsTables`()
BEGIN
DECLARE atsName VARCHAR(10);
DECLARE atsIndex INT;
SET atsIndex = 1;
SET #qry = '';
WHILE atsIndex > 0 DO
SET atsName =concat('ATS',atsIndex);
IF sf_is_table(atsName) = 1 THEN
Set #temp_qry = CONCAT('SELECT *, ''', atsName ,''' As TestPlatform FROM ', atsName, ' WHERE RequestNumber <> ''''' );
If #qry = '' THEN
SET #qry = #temp_qry;
ELSE
SET #qry = CONCAT(#qry, ' UNION ', #temp_qry);
END IF;
ELSE
SET atsIndex = -1;
END IF;
SET atsIndex = atsIndex + 1;
END WHILE;
DROP TABLE IF EXISTS ats_all;
SET #CreateTempTableQuery = CONCAT('CREATE TEMPORARY TABLE ats_all AS ', #qry ,'');
PREPARE stmt1 FROM #CreateTempTableQuery;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
ALTER TABLE ats_all DROP COLUMN ExecOrder;
ALTER TABLE ats_all ADD ExecOrder INT PRIMARY KEY AUTO_INCREMENT;
ALTER TABLE ats_all auto_increment = 0;
END
Here is the function I found online that checks if table exists in db.
DELIMITER $$
CREATE FUNCTION `sf_is_table`(`in_table` varchar(255)) RETURNS tinyint(4)
BEGIN
/**
* Check if table exists in database in use
*
* #name sf_is_table
* #author Shay Anderson 08.13 <http://www.shayanderson.com>
*
* #param in_table (table name to check)
* #return TINYINT (1 = table exists, 0 = table does not exist)
*/
# table exists flag
DECLARE is_table BOOLEAN DEFAULT FALSE;
# table count
DECLARE table_count INT DEFAULT 0;
# database name
SET #db = NULL;
# set database name
SELECT
DATABASE()
INTO
#db;
# check for valid database and table names
IF LENGTH(#db) > 0 AND LENGTH(in_table) > 0 THEN
# execute query to check if table exists in DB schema
SELECT COUNT(1) INTO table_count
FROM information_schema.`TABLES`
WHERE TABLE_SCHEMA = #db
AND TABLE_NAME = in_table;
# set if table exists
IF table_count > 0 THEN
SET is_table = TRUE;
END IF;
END IF;
RETURN is_table;
END
Conclusion:
Thank you everyone for your suggestions.
I decided to use Solution #2 since it does not cause as much impact to the db performance as Solution #3 and it does not require db redesign as Solution #1.
I don't think what you are doing will work like that. You should create an entity based on a single 'master' table, eg. Ats
Once you have done this you will have a property on your Entities class called Ats. You can now use this property to select the entities using a raw SQL query like this.
var atsName = "ats1";
using (var context = new Entities())
{
var blogs = context.Ats.SqlQuery(string.Format("SELECT * FROM {0}", atsName)).ToList();
}
Alternatively you could try this (I am assuming the property type is DBSet as you haven't specified it in the question)
var platform = propertyInfo.GetValue(ctx, null) as DBSet<Ats>;
atsPlatform = platform.Select(ats => new A new AtsPlatform { RequestNumber = ats.RequestNumber, NumberOfFail = ats.NumberOfFail, NumberOfFailWithCR = ats.NumberOfFailWithCR, NumberOfTestCase = ats.NumberOfTestCase }).ToList();
return atsPlatform;
Using LINQ to SQL in WCF I have a update record methods which ATM I manually assign each updated property.
Eg.
public void UpdateMachineRecord(Guid SessionID, int MachineRecordID, MachineRecord machineRecord)
{
if (!ValidSession(SessionID))
return;
using (MMHLINQSQLDataContext database = new MMHLINQSQLDataContext())
{
MachineRecord record = database.MachineRecords.Single(mr => mr.Job.OperationID == MachineRecordID);
record.ChangedBy = UserSession(SessionID).Name;
record.ChangedDate = DateTime.Now.ToString();
record.Date = machineRecord.Date;
record.EDI = machineRecord.EDI;
...
database.SubmitChanges();
}
}
My questions is: Is there a way to update the record using an entire entity?
Eg.
public void UpdateMachineRecord(Guid SessionID, int MachineRecordID, MachineRecord machineRecord)
{
if (!ValidSession(SessionID))
return;
using (MMHLINQSQLDataContext database = new MMHLINQSQLDataContext())
{
MachineRecord record = database.MachineRecords.Single(mr => mr.Job.OperationID == MachineRecordID);
record = machineRecord;
database.SubmitChanges();
}
}
You can do this.
database.MachineRecords.Attach(machineRecord, true);
database.SubmitChanges();
This will attach it as a modified entity (that's what the boolean parameter is for)