Combining multiple rows into one entity in Entity Framework 4.1 - c#

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

Related

Dynamic foreign key based on field value on another table

I have a database with many tables. Two of them are like this :
Table A
{
id int,
fkTable int,
fkClass int
}
Table B
{
id int,
reference varchar(100)
}
The A.fkTable field is a foreign key on another table, without particular constrains. We can only know on which table the relation is by B.reference field. The A.fkClass field point to the B.id field.
For example, if B.reference = "Operations", we can determinate that A.fkTable will point to Operations.id. We talk about 20 possibilities for B.reference value.
I know it's possible for Entity Framework to retrieve an specific entity by a field value, but I know only the way by a field in the same table.
Is there a solution in order to avoid manual joining in the code and EF retrieve the good mapped-object in function of B.reference value ? I think I need to declare manually my 20 entities in order to explain to EF the relationship between fkClass and the good table, but i'm not sure how coding the switch case.
And I don't want to do two queries : one in order to get the reference, and another in order to join fkTable to the good entity.
Edit : may can I use HasDiscriminator ?
Edit2 : I can't modify the database. I can only modify my C# project which connects to the database. It's not code-first. It's model-first.

Ways to update dbfirst Entity Framework model at runtime

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'.

Persisting Object Graph to SQL Server in a single transaction

I am having an issue coming up with a solution that I think must be a common problem to be solved by anyone writing to a database. I keep thinking that there is an obvious solution that I'm overlooking and that's why I can't find an appropriate existing question here.
Imagine a situation where you need to let a user create a "Class", with "Students", and each "Student" is assigned one or more books. You have a well defined hierarchy, Class->Student->Book.
You have the following tables:
CREATE TABLE Classes (
ClassId int identity(1,1) primary key,
ClassName nvarchar(255)
)
CREATE TABLE Students (
StudentId int identity(1,1) primary key,
ClassId int,
StudentName nvarchar(255),
StudentImage image
)
CREATE TABLE StudentBooks (
StudentBookId int identity(1,1) primary key,
StudentId int,
BookName nvarchar(255)
)
With this contrived scenario, what are my options for saving this entire graph of new objects, while letting SQL server assign the identity columns, and keeping it all in one transaction? Assuming that a class has maybe 30 students, and each student has several books assigned.
I could create a transaction and make a separate call for each row in each table, returning SCOPE_IDENTITY for each new parent object so I can save each child while keeping RI intact.
I could use XML. I would like to avoid that, as the graph includes a byte array.
Any other options? I thought about passing each level of the hierarchy in a table parameter. I'm not sure how or if that would work. (Wouldn't I have to define a table type for each of my tables, essentially duplicating the schema?)
I can use SQL server 2012 for this.
Thank you!
You can use Entity Framework to achieve what you want.
There are lots of tutorials out there, but a good starting point is this one:
MSDN on getting started with Entity Framework
or the linked page
MSDN overview page on getting started
I would recommend the EDMX approach for your use-case.

Need help building an Entity Framework 4 query

My context model has a couple of related tables:
CREATE TABLE "CarSystem"."Reads" (
"ReadId" UUID PRIMARY KEY,
. . .
);
CREATE TABLE "CarSystem"."Alarms" (
"AlarmId" UUID PRIMARY KEY DEFAULT UUID_GENERATE_V4(),
"ReadId" UUID NOT NULL REFERENCES "CarSystem"."Reads" ( "ReadId" ),
. . .
);
There are other columns, but they're not important. There is a zero to many relationship between the Reads table and the Alarms table. There can be any number of rows in the Alarms table for each row in the Reads table, from zero on up.
I've got an Entity Framework model for this database structure. I've also got a ViewModel object for the rows in the Reads table. I want the ViewModel object to have a boolean property called HasAlarms. This property is to be set to true if there is at least one row in the Alarms table for the row in the Reads table.
I've got a function in my data access layer which is supposed to return an array of Read ViewModel objects that all match a set of criteria. I'm not sure how to construct the query to set the HasAlarms property. I only want to go to the database once and I want one entry in the array for each row in the Reads table.
Right now I'm making two database queries, one to retrieve all of the Reads and another to retrieve all of the Alarms:
IQueryable<Read> query = from read in context.Reads
where SomeCondition
select read;
Alarm[] alarms = ( from read in query
join alarm in context.Alarms on read.Readid equals alarm.ReadId
select alarm ).ToArray();
ReadViewModel[] result = ( from read in query
select new ReadViewModel {
ReadId = read.ReadId,
. . .
HasAlarms = alarms.Where( a => a.ReadId == read.ReadId ).Any(),
. . .
} ).ToArray();
This works, but it's inefficient because I'm hitting the database twice, once to retrieve the rows in the Reads table and once to get the Alarms.
Is there a way to build this query so it only hits the database once?
Tony
#Craig Stuntz:
What I'm trying to do is to speed up the rate at which data is loaded in my application in response to a report request. This is a WPF application and I need the data to load as quickly as possible to improve the user experience. It's important to make as few trips to the database as possible or the application seems to crawl.
The ReadViewModel object consists of properties that map to columns in the table, plus a couple of nested objects that are either stored as columns in the same table or as rows in a couple of related tables. It is a complicated structure and Entity Framework complains if I try to create the View Model objets with one IQueryable. That is, something like:
ReadViewModel[] reads = ( from read in context.Reads
join alarm in context.Alarms on read.ReadId equals alarm.ReadId
where SomeCondition
select new ReadViewModel { ... } ).ToArray();
throws an exception that says Entity Framework can't create a constant of one of the nested types.
If I retrieve the data into arrays of Entity Objects and then create the View Model objects using Linq, everything works. But then I have to make more than one trip to the database to get everything. If I retrieve all of the data with those queries, though, it's a lot faster than letting Entity Framework go back and query for the extra data for each row, which is what happens when I do it the way you recommend. There's also the complication of having to do a left outer join with the Alarms table to mess things up.
I've found that if I retrieve the arrays of Entity Objects first, instead of making one trip for each row in addition to the initial trip, I can make 2 or 3 trips total. It's much faster than making n + 1 or n + 2 trips. I was just trying to see if there was a way I could get Entity Framework to do it all in one database call, which I could easily do if I were writing the SQL myself. I'd just have to add a column that returns 0 or 1 for HasAlarms if there was at least one row in the Alarms table for the Read.
Use the navigations/relationships in your model. It's usually wrong to spell out joins in L2E.
ReadViewModel[] result = ( from read in context.Reads
where SomeCondition
select new ReadViwModel
{
ReadId = read.ReadId,
// . . .
HasAlarms = read.Alarms.Any(),
// . . .
} ).ToArray();

Database doubly connected relationship inserting problem

I have two tables Plants and Information. For every plant there are many information, but for each plant there is a single MainInformation. So there is a one-to-many relationship and a one-to-one relationship between the two. The Information table has a PlantID and the Plants table has a MainInformationID. I want both fields in both tables not to be nulls. But now you can't insert either of the two records into their tables because each one requires their fields not be null, meaning they need the other record to be created first in order to create themselves. Perhaps this is not a good database design and something should be changed? (I am new to databases and entity framework)
I tried inserting into the database itself manually but I cant do it. I also tried this code with EntityFramework.
using (var context = new MyEntities())
{
var p = new Plant()
{
LatinName = "latinNameTest",
LocalName = "localNameTest",
CycleTime = 500
};
var i = new Information()
{
ShortDescription = "ShortDesc",
LongDescription = "LongDesc"
};
p.MainInformation = i;
i.Plant = p;
context.AddToPlants(p);
context.AddToInformation(i);
context.SaveChanges();
}
One of
The 1-1 FK column has to be NULL
The FK has to be disabled to allow parent insert before child
You have a single dummy Information row that is used by default in FL column
SQL Server does not allow deferred constraint checking without "code change" rights so even wrapping in a transaction won't work
Sounds like an EAV schema, which has other problems
You need to change the tables to allow for null. There is no other way to do this.
You may want to look at database transactions and how to use them with the Entity Framework. You can wrap both INSERTS into a single db transaction so the only results are both of them go in or neither go in.
Here is a link for transactions using EF. I didn't read through it but it seems to talk about them enough to get you started.

Categories