I have this sequence generation query that gets the current sequence and increment it to next value. But the increment is not updating. The nextval is always returning 1, the default value from the database
Entity | StartVal | Increment | CurVal | NextVal
----------------------------------------------------
INVOICE | 0 | 1 | 0 | 1
The nextval should be 3, 5, 7 and so on
int nextVal = 0;
using (var db = new MedicStoreDataContext())
{
DAL.LINQ.Sequence seq = (from sq in db.Sequences
where sq.Entity == entity
select sq).SingleOrDefault();
if (seq != null)
{
nextVal = seq.NextVal.HasValue ? seq.NextVal.Value : 0;
seq.NextVal = nextVal + 2;
db.SubmitChanges();
}
}
Have I left something undone?
UPDATE:
Answer: I needed to set the Primary Key and update Sequence class field to include the Primary Key
Usually this is because it hasnt found the unique identifier (or Primary Key) for a table.
In your data descriptions are you sure the table correctly picked up the unique item? - when I first tried this although I had a unique key etc, the table description in c# didnt mark it as unique, so the linq quietly didnt updated it as I had expected, no errors no warnings. Once I corrected the data table in c#, it all went well.
Isn't that the correct behaviour? wouldn't you expect nextVal to be 1 if CurVal is 0? I may be missing something here but it seems like your overcomplicating it a bit. Isn't what you want to do basically
using (var db = new MedicStoreDataContext())
{
DAL.LINQ.Sequence seq = (from sq in db.Sequences
where sq.Entity == entity
select sq).SingleOrDefault();
if (seq != null)
{
seq.CurVal += seq.Increment;
db.SubmitChanges();
}
}
I don't see why you need the whole nextVal bit at all. Please feel free to correct me if I'm wrong.
Related
I am working on application where I have a parent child relation between User and Orders tables. Below are the table structures:
User:
Column | DataType | Constraint
--------|-----------|-------------
UserId | int | Primary key
Username| varchar |
Email | varchar |
IsActive| bit |
Order:
Column | DataType | Constraint
--------|-----------|----------
OrderId | int | Primary key
UserId | int | Foreign key to User.UserId
Type | smallint |
Quantity| smallint |
As per the functionality I have to update User and his orders in one go where orders can be dynamically added, removed or updated.
I am using Entity Framework 6.0 and I cannot find any best solution to update parent table (user) and child table (order) in single transaction.
Could any one explain the best approach to achieve such functionality ?
Below is the code I am using:
Please take a note that I am using AutoMapper to map Object to Entity
public bool ManageUser(UserModel userDetails, string deletedOrders)
{
var isSuccess = false;
try
{
using (var entity = new UserEntity())
{
if (userDetails.UserId == 0)
{
entity.Users.Add(Mapper.Map<User>(userDetails));
}
else
{
var userToEdit = Mapper.Map<User>(userDetails);
foreach (var item in userToEdit.Orders)
{
if (item.OrderId == 0)
{
entity.Entry(item).State = System.Data.Entity.EntityState.Added;
}
else
{
entity.Entry(item).State = System.Data.Entity.EntityState.Modified;
}
}
/***
* How to Write a code here to remove orders using deletedOrders parameter
* Note: deletedOrders contains comma separated Id of the orders which needs to be removed. e.g. "1,5,6"
****/
entity.Entry(userToEdit).State = System.Data.Entity.EntityState.Modified;
}
entity.SaveChanges();
isSuccess = true;
}
}
catch (Exception ex)
{
}
return isSuccess;
}
Note: This is just a simple code. But what if I will have multiple child tables like Order ? If I would follow the same practice than code will become complex and hard to handle. So looking for best approach for such scenarios.
It is not necessary to make a trip to database for entities which should be deleted then.
If userDetails.Orders includes orders which should be deleted, you change their states inf your foreach (var item in userToEdit.Orders) cycle to System.Data.Entity.EntityState.Deleted.
If not, you simply create ones with suitable id's, attach them and then change their EntityState to Deleted as well:
var ordersToDelete = deletedOrders.Split(new[] {','},
StringSplitOptions.RemoveEmptyEntries).Select(x => new Order
{
Id = int.Parse(x.Trim())
})
.ToList();
ordersToDelete.ForEach(o =>
entity.Entry(x).State = System.Data.Entity.EntityState.Deleted);
Ok, so i have two questions. The first is, let's say that i have an EF called "EntitiesDefinitions", which holds a data table named "stringData" where each cell is defined as a varchar(100) like so:
----------------------------------------------
| | column1 | column2 | column3 | ... |
----------------------------------------------
| row1 | "1,2,3,4" | "5,6,7,8" | "9,a,b,c" | ... |
----------------------------------------------
| row2 | "d,e,f,g" | "h,i,j,k" | "l,m,n,o" | ... |
Each cell contains 4 pieces of information separated by a comma. So what i would like to know is, if there's a way for me to perform a Linq search for the (as an example) the 2rd piece of information of every cell in column1?
using (EntitiesDefinitions ef = new EntitiesDefinitions())
{
var v = (from a in ef.stringData where (a.column1... == "e") select a);
}
I know I could just make 4 columns per cell (column1_1, column1_2, ...column2_1, column2_2,...), but that wouldn't work if i get a table with +250 original columns. So is there a way to perform such searches?
The other question is also related to this. Back in ASP.NET i could send queries to my sql using a string like this:
var stringSql = "SELECT * FROM" + "stringData" + "WHERE ([" + "column1" + "] =" + "e" + ")" + "ORDER by ["+ "column1" +"] ASC;"
Basically, i could define which tables to search for given a string value that represented that property/column. Is there a way to do that with EF linqs?
using (EntitiesDefinitions ef = new EntitiesDefinitions())
{
var v = (from a in ef.stringData where (a.["column1"]... == "e") select a);
}
I'm fairly new with MVC and EF, so I would like to know if this is possible.
From what I understand from your question you can try this out if u sure its always not null:
var res = ef.stringData.Where(c => c.column1.Split(',')[1] == "e")
And for the Second Question where you type "ef.stringData" the name of the table you are querying is "stringData" there is no other way to specify the table name or only if you want to write raw sql queries in EF.
After Fehintola suggestion i was able to do more research specific to those subjects and I was able to find a solution for both questions. In case anyone is interested here's what i came up with:
For the first question, while is not elegant, we can encapsulate data inside in specific characters/delimiters and then we can process search results in nested searches. For example:
using (EntitiesDefinitions ef = new EntitiesDefinitions())
{
//Data could look like";1;*2*&3#"
var v = (from a in ef.stringData where select a); //to store the table
v = c.Where(f => f.column1.Contains("*2*")) //look for the second value
v = x.Where(f => f.column1.Contains("#4.3#"));//look for the forth value
//Do some other stuff...like sending the data to a table
}
For the Second question, you can make raw sql queries like this:
string sqlExample = #"SELECT VALUE a FROM ef.stringData AS a WHERE (a.column1 == '*2*')";
var test = ef.CreateQuery<stringData>(sql).AsQueryable();
This was you can just have variables placed in the sqlExample string to build your query dynamically and you'll get back a IQueryable object you can use to, for example, pass into a table.
I hope this helps someone in the future and thanks to everyone that provided suggestion.
I have a multithread environment and every thread wants to select a row (or insert it if it does not exist) in a table and increment something in it.
Basically, every thread does something like this :
using (var context = new Entity.DBContext()) {
if(!context.MyTable.Any(...)) {
var obj = new MyTable() {
SomeValue = 0
};
context.MyTable.Add(obj)
}
var row = context.MyTable.SingleOrDefault(...);
row.SomeValue += 1;
context.SaveChanges();
}
Problem in a example : a specific row has SomeValue = 0.
Two thread select this specific row at the same time, they both see 0.
-> they both increment it one time, and the final result in SomeValue will be 1, but we want it to be 2.
I assume that the thread that arrives just after the other should wait (using a lock ?) for the first one to be over. But i can't make it work properly.
Thanks.
Assuming SQL Server, you can do something like this:
create table T1 (
Key1 int not null,
Key2 int not null,
Cnt int not null
)
go
create procedure P1
#Key1 int,
#Key2 int
as
merge into T1 WITH (HOLDLOCK) t
using (select #Key1 k1,#Key2 k2) s
on
t.Key1 = s.k1 and
t.Key2 = s.k2
when matched then update set Cnt = Cnt + 1
when not matched then insert (Key1,Key2,Cnt) values (s.k1,s.k2,0)
output inserted.Key1,inserted.Key2,inserted.Cnt;
go
exec P1 1,5
go
exec P1 1,5
go
exec P1 1,3
go
exec P1 1,5
go
(Note, it doesn't have to be a procedure, and I'm just calling it from one thread to show how it works)
Results:
Key1 Key2 Cnt
----------- ----------- -----------
1 5 0
Key1 Key2 Cnt
----------- ----------- -----------
1 5 1
Key1 Key2 Cnt
----------- ----------- -----------
1 3 0
Key1 Key2 Cnt
----------- ----------- -----------
1 5 2
Even with multiple threads calling this, I believe that it should serialize access. I'm producing outputs just to show that each caller can also know what value they've set the counter to (here, the column Cnt), even if another caller immediately afterwards changes the value.
If only one process writes to the database at the same time, you could wrap your code in a C# lock(obj) {} statement. That limits you to one active query which will not make optimal use of the database, but if that's okay it's a simple solution.
Another option is to create a unique index on the columns that define whether the row already exists. If you insert over that, you'll get a duplicate key exception. You can catch that in C# and run an update instead.
If you can write raw SQL, you can use locking hints, for example with (updlock, holdlock), or set isolation level serializable. That probably gives you the best performance at the cost of complexity.
I am having a issue using TransactionScope and a check constraint in SQL Server.
I want to insert into the table as such:
Col A | Col B
------------
Dave | 0
Fred | 1
The table has a check constraint that there must always be an entry in Col B with '0'. The first row is inserting fine but the second row fails the constraint.
command.CommandText = #"INSERT INTO MyTable (ColA, ColB) VALUES(#ColA, #ColB)";
foreach (var row in model.Rows)
{
command.Parameters["#ColA"].Value = model.ColA;
command.Parameters["#ColB"].Value = model.ColB;
command.ExecuteNonQuery();
}
The check constraint calls the following function
IF EXISTS (SELECT * FROM mytable WHERE ColB = 0) RETURN 1
RETURN 0
Could this be because the constraint is only looking at committed data and if so how can it be told to look at uncommitted data as well
I don't think Check Constraints are suitable for a scenario like yours.You should use a instead of update/insert trigger to check that there's at least one row (in the table and /or in inserted values)
You have a inserted table in a trigger that contains all the rows that will be inserted so you can write something like this :
IF NOT EXISTS (SELECT * FROM mytable a UNION inserted WHERE ColB = 0) RIASEERROR("At least one row with ColB=0 should exist")
I've been asked to clean up someone else's controller code, which generates an invoice, and I've run into something I don't know how to fix. The code in question is as follows (this is using EF 6: Code First):
var invid = db.TransportJobInvoice.Where(c => c.CompanyId == CompanyId)
.Max(i => i.InvoiceId);
var invoiceId = invid == null ? 1 : (int)invid + 1;
The code is supposed to generate an invoiceId based on the company the invoice is being created for. So a small table of this might look as follows:
------------------------------
| Id | CompanyId | InvoiceId |
------------------------------
| 1 | 1 | 1 |
------------------------------
| 2 | 1 | 2 |
------------------------------
| 3 | 1 | 3 |
------------------------------
| 4 | 2 | 1 |
------------------------------
| 5 | 2 | 2 |
------------------------------
As you can see, the invoiceId would be generated based on the current number of invoices for the company in question. However, I think it's reasonable to suggest that two threads could execute the query before this line is evaluated:
var invoiceId = invid == null ? 1 : (int)invid + 1;
which would result in the same invoiceId being generated for two different invoices.
Is there a simple solution to this, possibly leveraging Entity Framework to do this automatically?
I suggest using the identity for the primary key, very important!
I would then add a column for "CustomerInvoiceID" and put a compound unique key on CustomerID and CustomerInvoiceID".
Then, create a stored procedure that will populate the field CustomerInvoiceID after it has been inserted, here is some pseudo code:
CREATE PROCEDURE usp_PopulateCustomerInvoiceID
#PrimaryKey INT, --this is your primary key identity column
#CustomerID INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #cnt INT;
SELECT #CNT = COUNT(1)
FROM TBL
WHERE CustomerID = #CustomerID
AND PrimaryKeyColumn <= #PrimaryKey
UPDATE tbl
SET CustomerInvoiceID = #cnt + 1
WHERE PrimaryKeyColumn = #PrimaryKey
END
Two possibilities:
Server-side: Don't compute the max(ID)+1 on the client. Instead, as part of the INSERT statement, compute the max(ID)+1, via an INSERT..SELECT statement.
Client-side: Instead of an incrementing int, generate a GUID on the client, and use that as your InvoiceID.
A rather different approach would be to create a separate table with the NextId for each CustomerId. As new customers are added you would add a new row to this table. It has the advantage that the numbers assigned to invoices can remain unique even if you allow deleting invoices.
create procedure GetInvoiceIdForCustomer
#CustomerId as Int,
#InvoiceId as Int Output
as
begin
set nocount on
begin transaction
update CustomerInvoiceNumbers
set #InvoiceId = NextId, NextId += 1
where CustomerId = #CustomerId
if ##RowCount = 0
begin
set #InvoiceId = 1
insert into CustomerInvoiceNumbers ( CustomerId, NextId ) values ( #CustomerId, #InvoiceId + 1 )
end
commit transaction
end
end
If you use an Identity field in SQL Server, this will be handled automatically.
I don't know if you can make the invoice id auto generated unless it's beinng threated as a foreign key (which I think it isn't).
You problem with multiple threads could be solved using a lock statement.
lock (myLock)
{
var invid = db.TransportJobInvoice.Where(c => c.CompanyId == CompanyId)
.Max(i => i.InvoiceId);
var invoiceId = invid == null ? 1 : (int)invid + 1;
}
This will guarantee that only thread is executing these statements.
Be careful though, this could cause performance issues when those statements are executed alot in parallel and the query takes some significant time to execute.