I would like to ask if it is possible to update database model (eg. columns) at runtime?
I've learned about Entity Framework (had to use database-first approach in my case) or Linq-to-SQL, but when database table changes, I have to update application's model manually.
In my application I would like to use MVVM pattern, so there must be a model class, which reflects a database table. As far as I know I can't add property to a class at runtime.
Here's example scenario:
Database table has 3 columns: col1, col2, col3
Model class has 3 properties: col1, col2, col3
Using Entity Framework I can get data from the database easily and then bind that data to controls eg. DataGrid
Application user is able to add new column to database
And there is a problem. I can't find any way to refresh model and then bind to DataGrid.
Question: is there any tools to help me solving problem from point 5 ?
I don't think you can do that with EF.
You could try with Dapper.
Execute a query and map it to a list of dynamic objects
public static IEnumerable<dynamic> Query (this IDbConnection cnn, string sql, object param = null, SqlTransaction transaction = null, bool buffered = true)
This method will execute SQL and return a dynamic list.
Example usage:
var rows = connection.Query("select 1 A, 2 B union all select 3, 4");
Assert.Equal(1, (int)rows[0].A);
Assert.Equal(2, (int)rows[0].B);
Assert.Equal(3, (int)rows[1].A);
Assert.Equal(4, (int)rows[1].B);
I still want it with EF
You could map data differently. Instead of new columns you could map the new data as a new value type in a related table and store values as rows, not columns.
This isn't ideal because you'd most likely end up storing the values as strings, but it could the job.
The table would look something like this.
CREATE TABLE CustomerDetails(
[CustomerId] [nvarchar](128) NOT NULL,
[Name] [nvarchar](128) NOT NULL,
[Value] [nvarchar](150) NOT NULL
(... setup keys, constraints, etc)
When the user creates a new column 'ColumnX', the values for this column are stored as rows with Name = 'ColumnX'.
Related
I have a view from some table when I select from the view in SQL Server Management Studio it works fine, but when I use Entity Framework to get the data from view it's different.
ReturnDbForTesEntities1 db = new ReturnDbForTesEntities1();
List<VJOBS2> list = new List<VJOBS2>();
list = db.VJOBS2.ToList();
Same number of records but last 2 rows are different.
I have table for job applicant applicant can apply for 2 jobs or more
ApplicantId ApplicantName JobId JobName
1 Mohamed 1 Developer
1 Mohamed 2 IT Supporter
but in list
ApplicantId ApplicantName JobId JobName
1 Mohamed 1 Developer
1 Mohamed 1 Developer
There is a subtle problem with views when used from Entity Framework.
If you have a table, do use it with EF, you need to have a primary key to uniquely identify each row. Typically, that's a single column, e.g. an ID or something like that.
With a view, you don't have the concept of a "primary key" - the view just contains some columns from some tables.
So when EF maps a view, it cannot find a primary key - and therefore, it will use all non-nullable columns from the view as "substitute" primary key.
I don't know what these are in your case - you should be able to tell from the .edmx model.
Let's assume that (ApplicantId, ApplicantName) are the two non-nullable columns that EF now uses as a "substitute" primary key. When EF goes to read the data, it will read the first line (1, Mohamed, 1, Developer) and create an object for that.
When EF reads the second line (1, Mohamed, 2, IT-Supporter), it notices that the "primary key" (1, Mohamed) is the same as before - so it doesn't bother creating a new object with those values read, but the primary key is the same, it hence must be the same object as it has already read before, so it uses that object instead.
So the problem really is that you can't have explicit primary keys on a view.
Either you can tweak your EF model to make it clear to EF that e.g. (ApplicantId, JobId) is really the primary key (you need to make sure those columns are both non-nullable) - or you need to add something like a "artificial" primary key to your view:
CREATE VIEW dbo.VJOBS2
AS
SELECT
ApplicantId, ApplicantName, JobId, JobName,
RowNum = ROW_NUMBER() OVER(ORDER BY JobId)
FROM
dbo.YourBaseTable
By adding this RowNum column to your view, which just numbers the rows 1, 2, ...., n, you get a new, non-nullable column which EF will include into the "substitute PK" and since those numbers are sequential, no two rows will have the same "PK" values and therefore none will erroneously be replaced by something that's been read from the database already.
FYI, I had to add ISNULL to get it to work for me, see the modification in the first line of this code example:
SELECT ISNULL(ROW_NUMBER() OVER(ORDER BY a.OrderItemID),0) as ident, a.*
FROM
(
SELECT e.AssignedMachineID, e.StartDate, e.OrderItemID, e2.OrderItemID AS doubleBookedEventID, e.StartTime, e.EndTime, e2.StartTime AS doubleBookedStartDateTime, e2.EndTime AS doubleBookedEndDateTime, DATEDIFF(MINUTE,e2.StartTime,e.EndTime) AS doubleBookedMinutes
FROM schedule e
INNER JOIN schedule e2
ON e.AssignedMachineID = e2.AssignedMachineID
and e.StartDate=e2.StartDate
AND e.schedID <> e2.schedID
AND e2.StartTime BETWEEN DATEADD(minute,1,e.StartTime) AND DateAdd(minute,-1,e.EndTime) where Coalesce(e.ManuallyOverrided,0)=0 and Coalesce(e.AssignedMachineID,0) > 0
) a
I'm in the point to implement an C# application that needs to consume already existing stored procedure that receive IDs or values in params.
My task in charge is in two steps:
1- migrate stored procedure in order to receive list of IDs(int) and list of current params, means like a table
2- implement the layer that cal this procedures and will receive List and KeyValuePair or KeyValuePair
What should be the best approach to do this ?
EntityFramework to wrap SPs or not ORM at alla?
How to implement List and KeyValuePair params ob SP side ? with Table-Valued params ?
I'm with SQL 2012
thanks,
Try in sql side User defined table type functionality and pass table as parameter in stored procedure.
For example:
CREATE TABLE Test
(
Id int NOT NULL IDENTITY (1, 1),
TestName varchar(50) NOT NULL,
Value int NULL
) ON [PRIMARY]
-- Create a table data type
CREATE TYPE [dbo].[TestType] As Table
(
--This type has structure similar to the DB table
TestName varchar(50) NOT NULL,
Value int NULL
)
--This is the Stored Procedure
CREATE PROCEDURE [dbo].[TestProcedure]
(
#Test As [dbo].[TestType] Readonly
)
AS
Begin
Insert Into Test(TestName,Value)
Select TestName, Value From #Test
End
C# code passing the data as follows:
DataTable dataTable = new DataTable("SampleDataType");
// We create column names as per the type in DB
dataTable.Columns.Add("TestName", typeof(string));
dataTable.Columns.Add("Value", typeof(Int32));
// And fill in some values
dataTable.Rows.Add("Metal", 99);
dataTable.Rows.Add("HG", null);
...
SqlParameter parameter = new SqlParameter();
// The parameter for the SP must be of SqlDbType.Structured
parameter.ParameterName="#Test";
parameter.SqlDbType = System.Data.SqlDbType.Structured;
parameter.Value = dataTable;
command.Parameters.Add(parameter);
I dealt with this same issue just recently. The links in the comments above lay out how to do SPs with table valued parameters. I've used the TVP method and it was easy and clean.
When it comes to Entity Framework, you can make EF aware of the Stored Procedures and call them and get the results back into EF Objects. Here's a link:
http://msdn.microsoft.com/en-us/data/gg699321.aspx
It's quite a bit more work than just calling the SPs with ADO. A major consideration is whether the results returned by the SP map directly onto one of your objects. Suppose you're joining a couple of tables in a search. You'd have to make a new model for those results and map the SP to that model and for what? So everything will run slower.
If you're just reading data and the results don't map exactly to an existing model you should skip EF and use ADO directly. If, OTOH, you're doing reads and writes and you really want to keep everything in EF for consistency's sake, it is possible.
I've been trying to grow my EF understanding from just querying tables to creating Entities that match my business objects so I can code against my business objects rather than my data objects. I read articles that suggest this is possible, but all of their examples are rather trivial and involve just combining two tables. My situation is a little more complicated and I'm not sure how to proceed.
I have two tables (simplified below)
CREATE TABLE [dbo].[BarEvents]
(
[BarGUID] UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(),
[Bar] INT NULL
)
CREATE TABLE [dbo].[BarLog]
(
[BarGUID] UNIQUEIDENTIFIER NOT NULL,
[BarLogGUID] UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(),
[BarEventTime] DATETIME NOT NULL DEFAULT GETUTCDATE()
)
So if I join these tables, for a specific BarGUID, so if I had 1 Bar and 4 bar events logged, I'd have 4 rows, but what I want is just the most recent BarEventTime. So I would like to join and have just one row:
I can do this trivially in EF:
var query = barEntities.BarEvents.Where( q=> q.BarGUID = '0000-0000-0000-0000')
.Select(barEvent =>
new LogItem()
{
Bar = barEvent.Bar,
BarEventTime = barEvent.BarLog.Max(u => u.BarEventTime)
});
But from what I've read, I should be able to define a LogItem entity, and place this logic somehow in my LogItem entity, then write queries against that. My problem is I only see trivial join conditions when I'm trying to join my tables in the entity definitions. Is there a way to do this? Or a guide?
Any help would be appreciated.
Thank you.
Why don't you do the following:
Create a SQL View in the Database that does what you want
Add the view to your EF Context
Use the newly created entity that is based on the view
A database exists with two tables
Data_t : DataID Primary Key that is
Identity 1,1. Also has another field
'LEFT' TINYINT
Data_Link_t : DataID PK and FK where
DataID MUST exist in Data_t. Also has another field 'RIGHT' SMALLINT
Coming from a microsoft access environment into C# and sql server I'm looking for a good method of importing a record into this relationship.
The record contains information that belongs on both sides of this join (Possibly inserting/updating upwards 5000 records at once). Bonus to process the entire batch in some kind of LINQ list type command but even if this is done record by record the key goal is that BOTH sides of this record should be processed in the same step.
There are countless approaches and I'm looking at too many to determine which way I should go so I thought faster to ask the general public. Is LINQ an option for inserting/updating a big list like this with LINQ to SQL? Should I go record by record? What approach should I use to add a record to normalized tables that when joined create the full record?
Sounds like a case where I'd write a small stored proc and call that from C# - e.g. as a function on my Linq-to-SQL data context object.
Something like:
CREATE PROCEDURE dbo.InsertData(#Left TINYINT, #Right SMALLINT)
AS BEGIN
DECLARE #DataID INT
INSERT INTO dbo.Data_t(Left) VALUES(#Left)
SELECT #DataID = SCOPE_IDENTITY();
INSERT INTO dbo.Data_Link_T(DataID, Right) VALUES(#DataID, #Right)
END
If you import that into your data context, you could call this something like:
using(YourDataContext ctx = new YourDataContext)
{
foreach(YourObjectType obj in YourListOfObjects)
{
ctx.InsertData(obj.Left, obj.Right)
}
}
and let the stored proc handle all the rest (all the details, like determining and using the IDENTITY from the first table in the second one) for you.
I have never tried it myself, but you might be able to do exactly what you are asking for by creating an updateable view and then inserting records into the view.
UPDATE
I just tried it, and it doesn't look like it will work.
Msg 4405, Level 16, State 1, Line 1
View or function 'Data_t_and_Data_Link_t' is not updatable because the modification affects multiple base tables.
I guess this is just one more thing for all the Relational Database Theory purists to hate about SQL Server.
ANOTHER UPDATE
Further research has found a way to do it. It can be done with a view and an "instead of" trigger.
create table Data_t
(
DataID int not null identity primary key,
[LEFT] tinyint,
)
GO
create table Data_Link_t
(
DataID int not null primary key foreign key references Data_T (DataID),
[RIGHT] smallint,
)
GO
create view Data_t_and_Data_Link_t
as
select
d.DataID,
d.[LEFT],
dl.[RIGHT]
from
Data_t d
inner join Data_Link_t dl on dl.DataID = d.DataID
GO
create trigger trgInsData_t_and_Data_Link_t on Data_t_and_Data_Link_T
instead of insert
as
insert into Data_t ([LEFT]) select [LEFT] from inserted
insert into Data_Link_t (DataID, [RIGHT]) select ##IDENTITY, [RIGHT] from inserted
go
insert into Data_t_and_Data_Link_t ([LEFT],[RIGHT]) values (1, 2)
I'm building an ASP.NET MVC site that uses LINQ to SQL to connect to SQL Server, where I have a table that has an IDENTITY bigint primary key column that represents an ID.
In one of my code methods, I need to create an object of that table to get its ID, which I will place into another object based on another table (FK-to-PK relationship).
At what point is the IDENTITY column value generated and how can I obtain it from my code?
Is the right approach to:
Create the object that has the IDENTITY column
Do an InsertOnSubmit() and SubmitChanges() to submit the object to the database table
Get the value of the ID property of the object
The identity will only be generated when you call SubmitChanges, so your approach listed is a viable option.
What you can do however is to set the FK object rather than ID on the other object and LINQ to SQL will work it out for you.
EG: If TableA.TableBID is an FK to TableB.TableBID then you're referring to taking:
TableB b = new TableB();
context.TableB.InsertOnSubmit(b);
context.SubmitChanges();
TableA a = new TableA();
a.TableBID = b.TableBID;
context.TableA.InsertOnSubmit(a);
context.SubmitChanges();
But you can do it in a single submit by setting the object for the FK like this:
TableB b = new TableB();
context.TableB.InsertOnSubmit(b);
TableA a = new TableA();
a.TableB = b;
context.TableA.InsertOnSubmit(a);
context.SubmitChanges();
Which isn't much shorter code-wise in this example, but it does allow only 1 spot where you commit which is typically a good thing structurally.