Best way to access data in related tables - c#

I have two tables that are conceptually related but the original coder did not create any FK relationship between the tables.
Table1:
TABLE [Name](
ID [varchar](10) NOT NULL (this is the PK),
MAIL_ADDRESS_NUM [int] NOT NULL,
BILL_ADDRESS_NUM [int] NOT NULL,
Shipping_Address_Num [int] Not Null
)
Table2:
TABLE [Address](
ID [varchar](10) NOT NULL,
ADDRESS_NUM [int] NOT NULL (this is the PK),
PURPOSE [varchar](20) NOT NULL
)
If I had the option I would put FKs on the MailingAddress to AddressNumber, BillingAddress to AddressNumber, and ShippingAddress to AddressNum. But that is not an option.
Currently in my LINQ I do something like:
from n in Names.Where(predicate)
join ba in db.Addresses on n.BillingAddressNumber equals ba.AddressNumber
join sa in db.Addresses on n.ShippingAddressNumber equals sa.AddressNumber
join ma in db.Addresses on n.MailingAddressNumber equals ma.AddressNumber
If I understand EF and linq correctly I should be able to make that association in/on the Edmx design surface and simplify my query. Correct?
If so what steps need to be taken to add the correct associations to the Edmx files? I have found some references but they seem to involve a fair amount of manipulating the underlying XML files. Is that necessary? Also these tables are strictly read-only. Using VS2012 and EF5.

Related

Generic linq queries with exclusion filters

I have a pattern in my database tables for soft deleting. I want to generate Linq queries to fetch data that is not expired.
For example with the two tables below, a User can have multiple addresses. An address can be soft deleted by setting the SoftDeleteDate to Datetime.Now. When fetching the User we can create a query to exclude UserAddress where UserAddress.SoftDeleteDate is not null.
TABLE [dbo].[User](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[FirstName] [nvarchar](25) NOT NULL,
[SoftDeleteDate] [datetimeoffset](7) NULL
)
TABLE [dbo].[UserAddress](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[UserId] [bigint] NOT NULL,
[StreetName] [bigint] NOT NULL,
[City] [nvarchar](50) NULL,
[State] [nvarchar](50) NULL,
[SoftDeleteDate] [datetimeoffset](7) NULL
)
This is a simple use case. In practice an entity such as a user can be linked to child entities to several degrees of nesting.
Generic methods for fetching can be easily created using DbContext. These methods fetch nested entities using "Include". But linq has no concept of "Exclude"
T GetDataById<T>(long id)
{
return Context.Set<T>().Find(id);
}
I want to create a generic method that produces Linq queries that excludes any expired child entities to no more than three degrees of nesting. This way, when I fetch a User I can exclude expired UserAddresses.
I have seen some posts about PredicateBuilder http://www.albahari.com/nutshell/predicatebuilder.aspx but not sure if it can be used to generate a query with the needed filter.
Wondering if anyone out there has worked on this problem.

Can't access Entity Framework table with no primary key

I am creating an application to transfer data from one database into another for a new application and I am running into an issue access some of the data in the old database. The old database was created using Ruby on Rails and they way it was designed and created through Rails, the database in SQL Server has no primary keys and all the columns are nullable. The new database was designed and built in SQL Server with proper keys and nullable columns. Since both databases are in SQL Server I wanted to use Entity Framework Database First to make the data transition easier.
In the EF Desginer I was able to assign entity keys to all of the tables except for one (Response), which is keeping me from correctly accessing the data in the table. The table definition is as follows:
assess_id [int] NULL
person_id [int] NULL
question_id [int] NULL
question_version [int] NULL
answer_id [int] NULL
answer_version [int] NULL
text [nvarchar(4000)] NULL
created_at [datetime] NOT NULL
updated_at [datetime] NOT NULL
Because of the allowed records the primary key should consist of
assess_id
person_id
question_id
question_version
answer_id
answer_version
but there may be multiple answer_id and answer_version records to the same question_id and question_version or the answer_id and answer_version are null so I cannot use that. Any subset of this key would not allow me to properly retrieve all the data. Also I cannot use the created_at or updated_at columns as there are multiple instances of rows being written with the same time stamp.
I only need to read the data, not write, since it is being transformed into the new database and there is no way for me to change the existing database. Is there any way around the key issue?
Before I answer I would like to point out that this solution only works for read-only situations and if you need to write to the table it will not help. In that case I point you to this answer where you will find some help.
I managed to find a work around for this scenario and while easy enough to use, I would not consider it optimal.
In order to get around the key issue, I picked a primary key that would at least not fail a null check, in this case just the assess_id and person_id columns. This let me build without any errors but I still could not retrieve all the data correctly.
The workaround is to use a SqlQuery on the database.
var responses = context.Database.SqlQuery<Response>("SELECT * FROM dbo.responses");
This executed the query on the whole database and casted the result set into a list of responses with the correct data. Make sure you execute the query on the database and not the table, otherwise the incorrect key specified in the designer will be used and you won't get the correct data back.
Put your SQL in a stored procedure and call that from your application.
If you cannot modify the source database, you can put the stored procedure in the destination.

Add a field to a relation table and access row values through code

Using EF code first and Fluent, I've created two tables containing data and a third table which is the "relation table" (not sure what the 'official' word for it is?). Each row holds Id's from both tables and defines a many-to-many relation between the two.
The tables hold purchase orders and products. Now I need to specify the amount of products in a purchase order as well, so my most logical conclusion was to add a field in the relation table that specifies the quantity, so that the table will become:
orderId | productId | quantity
83923 | 867392 | 100
83923 | 865392 | 250
83923 | 323392 | 50
Is this possible using EF code first? I couldn't find a way, but it's hard to search for a solution since I find it hard to concisely describe what I need to do.
I thought I could add a field using the designer, which works, but I have no idea how to access the value through code now.
My tables:
The field/table names are all in Dutch, but hopefully it's understandable & readable.
-- Purchase orders
CREATE TABLE [dbo].[InkoopOrders] (
[InkoopOrderId] INT IDENTITY (1, 1) NOT NULL,
[Kenmerk] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_dbo.InkoopOrders] PRIMARY KEY CLUSTERED ([InkoopOrderId] ASC)
);
-- Products
CREATE TABLE [dbo].[Artikelen] (
[ArtikelId] INT IDENTITY (1, 1) NOT NULL,
[Kenmerk] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_dbo.Artikelen] PRIMARY KEY CLUSTERED ([ArtikelId] ASC)
);
-- Relation table
CREATE TABLE [dbo].[InkoopOrderArtikel] (
[InkoopOrderId] INT NOT NULL,
[ArtikelId] INT NOT NULL,
CONSTRAINT [PK_dbo.InkoopOrderArtikel] PRIMARY KEY CLUSTERED ([InkoopOrderId] ASC, [ArtikelId] ASC),
CONSTRAINT [FK_dbo.InkoopOrderArtikel_dbo.InkoopOrders_InkoopOrderId] FOREIGN KEY ([InkoopOrderId]) REFERENCES [dbo].[InkoopOrders] ([InkoopOrderId]) ON DELETE CASCADE,
CONSTRAINT [FK_dbo.InkoopOrderArtikel_dbo.Artikelen_ArtikelId] FOREIGN KEY ([ArtikelId]) REFERENCES [dbo].[Artikelen] ([ArtikelId]) ON DELETE CASCADE
);
This was achieved through creating the two models, and defining the relation in Fluent:
modelBuilder.Entity<InkoopOrder>()
.HasMany(o => o.Artikelen)
.WithMany(a => a.InkoopOrders)
.Map(
m => {
m.MapLeftKey("InkoopOrderId");
m.MapRightKey("ArtikelId");
m.ToTable("InkoopOrderArtikel");
}
);
In EF, in may to many relationships, the association table can only have the Key columns of the related tables. So, no, you cannot do that with a many to many using EF. If you wanted to do this, you'd need to specify two one-to-may relationships (from both many to many tables, to the association table). Look at this SO answer for a full explanation.
However, I don't understand why you want to use a many to many. You simply need to use the classical Order table with a child OrderDetail table that has the ProductId, UnitPrice, Units, Total, and so on. Forget about using the many to many for this case. It's much easier in this way.

In Entity framework load child in parent entity (non primary key association)

I am very new to Entity Framework and so I don't know the technical terms use in it. I am sorry for my bad English.
I am working in a project which has entity framework in it and has an .edmx file. The file has entities created in it.
So I created 2 entities and named it TableA and TableB.
pid is entity key of TableA and cid is entity key of TableB .
And created many to one relationship in it.
i.e. TableA row1 can have TableB_cid=1
TableA row2 can also have TableB_cid=2
And then I did "Generate database from model"
CREATE TABLE [TableA] (
[pid] nvarchar(max) NOT NULL,
[name] nvarchar(max) NOT NULL,
[TableB_cid] nvarchar(max) NOT NULL
);
GO
CREATE TABLE [TableB] (
[cid] nvarchar(max) NOT NULL,
[name] nvarchar(max) NOT NULL
);
pid|name|TableB_cid
--------------------
1 | a | 2
2 | b | 2
3 | c | 1
cid|name
------------
1 | s
2 | f
Now in the C# code i wrote this,
TableA obj = repository.All().Single(w=>w.pid == "1")
context.Entry<TableA>(obj).Reference<TableB>(o => o.TableB).Load();
Now this will load the TableB whose cid=1 (but what i actually wanted was to load TableB whose cid=2).
I think its matching primary key to primary key and not TableB_cid (TableA) to cid (TableB).
So what i am doing wrong please help.
Edit:
In short I am looking for a way where I can add association of a Non Primary column of table A with a Primary column of table B in Entity Framework 4.0.
And I don't want to use linq queries and joins. I have tried but I cant a find a way or option in edmx file where i can do it.
Thanks,
M
I'm not sure I understand the question, but in your example, are you simply attempting to access the TableB entity of the TableA with Id 1?
If so, how about this:
TableA obj = repository.All().Single(w=>w.pid == "1");
TableB SecondTable = obj.TableB;
SecondTable.cid should be 2, is and obj.pid should be 1. If not, what values are you getting?
var childs = from c in context.Children
where c.cid = o.Child_cid;
I think that should help you.

NHibernate Join Table with Non Primary Key

I am trying to do a one to one join with 2 tables using non-primary fields.
I have 2 tables in the DB.
CREATE TABLE [dbo].[Branch](
[BranchID] [int] IDENTITY(1,1) NOT NULL,
[Branch_Name] [nvarchar](100) NULL)
CREATE TABLE [dbo].[Salesman](
[SalesmanID] [int] IDENTITY(1,1) NOT NULL,
[BranchID] [int] NOT NULL,
[First_Name] [nvarchar](30) NULL,
[Last_Name] [nvarchar](30) NULL)
I basically need the Branch Name whenever I retrieve a row from the salesman table.
I thought I could add a join in the Salesman.hbm.xml file.
<join table="dbo.Branch">
<key column="BranchID" />
<property lazy="true" update="false" insert="false" not-null="false" type="String" name="Branch_Name" />
</join>
This did not work because nHibernate always created a join with the primary key. I read some other posts and they suggested using a view for situations like this. So I created a view like so:
create view dbo.VIEW_Salesman As
SELECT a.[SalesmanID], a.[BranchID], a.[First_Name],a.[Last_Name],
(select [Branch_Name] FROM [dbo].[Branch] WHERE BranchID= a.[BranchID]) As Branch_Name
FROM [dbo].[Salesman] as a
The above view actually works but is there a better solution when you want to join 2 tables using non-primary fields?
Thanks in advance for any suggestions and advice,
Have a great day!
You could either use Dependancy Injection which actually has nothing to do with NHibernate, and would definitely force a change in your mapping file, or perhaps use a named query in the NHibernate configuration file.
Besides, I just thought that you perhaps could use composite mapping while using Dependancy Injection.
Salesman s = new Salesman(branchInstance)
So you should have a Branch property within your Salesman class that could allow you to know the branch name to which this salesman belongs. Otherwise, simply have a BranchName property which would actually return the branchInstance.Name property value.
See the following for Component Mapping using NHibernate:
NHibernate Mapping - ;
NHibernate - Chapter 7 - Component Mapping;
NHibernate Reference Documentation.
Or if you prefer to make it as a view using NHibernate, perhaps a named query should do it with less of a change:
16.2. Named SQL queries.
Hope this helps! Do not hesitate to ask further details, I'll be pleased to assist you furhter if I can! =)

Categories