Using a view with no primary key with Entity - sql

I just started on a project converting an application from raw ADO.NET and embedded SQL to Entity. I ran in to a problem with one of the views used by the application. The view has no primary key and no column (or combination of columns) that uniquely identifies a row. Here is the select the view is created with:
SELECT
filingmonth,
CEIL(filingmonth / 3),
licnum,
filingyear,
DECODE(GROUPING(insurername), '1', '- All Insured -', insurername),
insurername,
policylinecode,
linedescription,
SUM(NVL(grosspremium, 0)),
SUM(DECODE(taxexempt, 1, grosspremium, 0)),
TRUNC(
CASE
WHEN
(
b.rsn IS NOT NULL
OR A.zeroreport = 1
)
AND b.datereceived IS NULL
THEN A.datereceived
ELSE b.datereceived
END),
SUM(aip.iscompanyadmitted(b.naiccocode, b.naicalienid)),
A.insuredid
FROM
aip.slbtransinsured A
LEFT OUTER JOIN aip.slbtransinsurer b
ON
A.insuredid = b.insuredid
LEFT OUTER JOIN aip.slblinecodes C
ON
b.policylinecode = C.linecode
WHERE
A.submitted = 1
AND A.entryincomplete = 0
GROUP BY
licnum,
filingmonth,
filingyear,
TRUNC(
CASE
WHEN
(
b.rsn IS NOT NULL
OR A.zeroreport = 1
)
AND b.datereceived IS NULL
THEN A.datereceived
ELSE b.datereceived
END),
ROLLUP(insurername, aip.iscompanyadmitted(b.naiccocode, b.naicalienid),
policylinecode, linedescription), A.insuredid;
And here is some sample data showing that there are some rows that are completely duplicated (rows 3 and 4):
FILINGMONTH CEIL(FILINGMONTH/3) LICNUM FILINGYEAR DECODE(GROUPING(INSURERNAME),'1','-ALLINSURED-',INSURERNAME) INSURERNAME POLICYLINECODE LINEDESCRIPTION SUM(NVL(GROSSPREMIUM,0)) SUM(DECODE(TAXEXEMPT,1,GROSSPREMIUM,0)) TRUNC(CASEWHEN(B.RSNISNOTNULLORA.ZEROREPORT=1)ANDB.DATERECEIVEDISNULLTHENA.DATERECEIVEDELSEB.DATERECEIVEDEND) SUM(AIP.ISCOMPANYADMITTED(B.NAICCOCODE,B.NAICALIENID)) INSUREDID
6 2 8150 2007 SAVERS PROPERTY AND CASUALTY INSURANCE CO SAVERS PROPERTY AND CASUALTY INSURANCE CO 17 OTHER LIABILITY 721.25 0 18-JUL-07 0 81
6 2 8150 2007 SAVERS PROPERTY AND CASUALTY INSURANCE CO SAVERS PROPERTY AND CASUALTY INSURANCE CO 17 721.25 0 18-JUL-07 0 81
6 2 8150 2007 SAVERS PROPERTY AND CASUALTY INSURANCE CO SAVERS PROPERTY AND CASUALTY INSURANCE CO 721.25 0 18-JUL-07 0 81
6 2 8150 2007 SAVERS PROPERTY AND CASUALTY INSURANCE CO SAVERS PROPERTY AND CASUALTY INSURANCE CO 721.25 0 18-JUL-07 0 81
insuredid is the pk for the aip.slbtransinsured table, rsn is the pk for aip.slbtransinsurer and aip.slblinecodes.
Is it at all possible to add a view to the Entity model without a unique identifier? Or is there an easy way to add a unique row identifier to the view? The view is only read from, never written to.

Is it at all possible to add a view to the Entity model without a
unique identifier?
If without a primary key, no. That will result to this kind of error:
One or more validation errors were detected during model generation:
System.Data.Edm.EdmEntityType: : EntityType 'SalesOnEachCountry' has
no key defined. Define the key for this EntityType.
System.Data.Edm.EdmEntitySet: EntityType: The EntitySet
SalesOnEachCountryList is based on type SalesOnEachCountry that has no
keys defined.
If without a unique identifier, yes, albeit it has a non-desirable output. Records with same identifier would reference the same object, this is called Identity Map Pattern
An example, even if your view produces these two rows:
Country Year TotalSales
Philippines 2010 20.000000
Philippines 2011 40.000000
If you will just map the primary key on Country field only, e.g.
public class SalesOnEachCountry
{
[Key]
public int CountryId { get; set; }
public string CountryName { get; set; }
public int OrYear { get; set; }
public long SalesCount { get; set; }
public decimal TotalSales { get; set; }
}
, even your view produces the above two rows on your Oracle query editor, Entity Framework produces this incorrect output:
Country Year TotalSales
Philippines 2010 20.000000
Philippines 2010 20.000000
Entity Framework will take it that the second row is same object as first row.
To guarantee uniqueness, you must identify what columns that makes each row unique. In the above example, Year must be included so the primary key is unique. i.e.
public class SalesOnEachCountry
{
[Key, Column(Order=0)] public int CountryId { get; set; }
public string CountryName { get; set; }
[Key, Column(Order=1)] public int OrYear { get; set; }
public long SalesCount { get; set; }
public decimal TotalSales { get; set; }
}
Making your primary key similar to the attributes above, Entity Framework can correctly map your each view's row to their own objects. Hence, Entity Framework can now display exactly the same rows your view have.
Country Year TotalSales
Philippines 2010 20.000000
Philippines 2011 40.000000
Full details here: http://www.ienablemuch.com/2011/06/mapping-class-to-database-view-with.html
Then regarding your views which don't have any columns to make a row unique, the easiest way to guarantee Entity Framework can map each of your view's row to their own objects is to create a separate column for your view's primary key, a good candidate is to just create a row number column on each row. e.g.
create view RowNumberedView as
select
row_number() over(order by <columns of your view sorting>) as RN
, *
from your_existing_view
Then assign the [Key] attribute on RN property of your class RowNumberedView

Expanding on the answer from Michael Buen:
I found that adding the row number to the view with an ISNULL() will allow the entity framework to pull the view in and create the necessary EntitySet data automatically.
create view RowNumberedView as
select
ISNULL(ROW_NUMBER() OVER (ORDER BY <column>), 0) AS RN
, *
from your_existing_view

At work recently, i ran into this same issue. Based on my research, I could not find any answers on how to attach a view to EF6 CodeFirst without a PK. Most seem to involve migrations and were quite confusing. I believe DB first has better support for working SQL VIEWS.
I did try introducing a window function (RowNumber) with the idea being, to use the row identifier as the PK to keep EF6 Happy. But this made my query more expensive overall so i had to drop this idea.
In the end, I had to carefully analyse my data set to see if i could introduce a composite key - one that covers all of the scenarios my business application needed to ensure would work. Remember to use IsNull(ColumnName,0) too to ensure you can satisfy the .IsRequired() in CodeFirst fluent methods.
i.e
HasKey(x => new { x.KfiId, x.ApplicationNumber, x.CustomerId });
I hope this helps someone - the answer for me was analyse the dataset the view denormalises and look for a composite key.
Another cool idea you can try suggested by Marc Cals.

In case you are using Entity Framework with MVC in ASP.NET
As previously said, create your view with column that has auto-increment or ROW_NUMBER.
Let's say you have that column and it's name is rowNumber.
an than go to context file (yourDatabaseNameContext) file in your Models directory of your MVC application, find definition for your view and instead of
modelBuilder.Entity<yourView>(entity =>
{
entity.HasNoKey();
change it to:
modelBuilder.Entity<yourView>(entity =>
{
entity.HasKey(e => e.rowNumber);

Is it at all possible to add a view to the Entity model without a unique identifier?
It's possible to have a views where there isn't a single column or set of columns that create the primary key; thus, you end up with spurious relationships. Data warehouse tables sometimes follow that form. In short, normalization is sometimes not followed for either performance reasons or reporting reasons.
Now to your second point:
Or is there an easy way to add a unique row identifier to the view?
What i suggest you do is to select all the columns from slbtransinsured and see if you can find the one column that uniquely identifies each record. It seems to me that the data is there should be a code type in slblinecodes that you need to select, somewhat like a lookup.
For kicks, try running this and tell me what you get:
SELECT filingmonth,
CEIL (filingmonth / 3),
licnum,
filingyear,
DECODE (GROUPING (insurername), '1', '- All Insured -', insurername),
insurername,
policylinecode,
linedescription,
SUM (NVL (grosspremium, 0)),
SUM (DECODE (taxexempt, 1, grosspremium, 0)),
TRUNC (
CASE
WHEN (b.rsn IS NOT NULL OR a.zeroreport = 1)
AND b.datereceived IS NULL
THEN
a.datereceived
ELSE
b.datereceived
END),
SUM (aip.iscompanyadmitted (b.naiccocode, b.naicalienid)),
a.insuredid
FROM aip.slbtransinsured a
LEFT OUTER JOIN aip.slbtransinsurer b
ON a.insuredid = b.insuredid
LEFT OUTER JOIN aip.slblinecodes c
ON b.policylinecode = c.linecode
WHERE a.submitted = 1 AND a.entryincomplete = 0
GROUP BY filingmonth,
licnum,
filingyear,
DECODE (GROUPING (insurername), '1', '- All Insured -', insurername),
insurername,
policylinecode,
linedescription,
TRUNC (
CASE
WHEN (b.rsn IS NOT NULL OR a.zeroreport = 1)
AND b.datereceived IS NULL
THEN
a.datereceived
ELSE
b.datereceived
END),
a.insuredid;

Consider using AsNoTracking() when consuming the view. This disables the usage of any key fields for EF tracking. Then any non-null field can be defined manually as the EF key (even if it repeats).
It is advised not to create an additional row counter field because most row counters end up requiring that the engine scan the entire domain of the view to generate the proper counter values even if querying using a predicate (where clause).
Please see link.

Related

DDD - Update Value Object in Database with FK dependencie

I am reading about DDD and I have learned that Value Object is immutable, if you want to change it, you will have to create a new one.
I have just read the information on How are Value Objects stored in the database? , it works well for Address class and I also read https://cargotracker.java.net/ and https://gojko.net/2009/09/30/ddd-and-relational-databases-the-value-object-dilemma/. But I want to do something different .
I am working on a billing system , it has 4 tables/classes
TPerson - fields: id_person, name -> <<Entity>>
TMobile - fields: id_mobile, number -> <<Entity>>
TPeriod - fields: id_period, id_person, id_mobile, begin_date, end_date -> <<Value Object>> (I think, because the dates can be change)
TCall - field: id_call, id_period, etc... -> <<Value Object>>
The table TCall has many records, if I change the period record dates (Value Object, table TPeriod) it will create another Object Period then id_period will change(delete, insert a record) , but the foreign key in table TCall will be violated. How Could I implement the period class ? if i implement as a value object , it will be immutable and turns out I will not be able to change anything whatsoever.
Thanks,
Fernando
if it's a value object you don't have a period table/id.
A value object is just a grouping of certain fields. For example a call might have a start time, an end time, and then you could create a Duration Value object with starttime and end time from the call table. In your java code it would be then more convenient to talk about the call duration instead of the start/end time separately.
However, it certainly could make sense to make period an entity, but then period 201601 probally always have the same start/end time and you wouldn't need to make changes to it. And if you did you make changes to the entity directly and keeping the ids in tact.
Thank for your help,
I have this situation:
TPerson - fields: id_person = 1 , name = "John"
TMobile - fields: id_mobile = 100, number "555-0123"
TPeriod - fields: id_period = 1000, id_person = 1 , id_mobile = 1, begin_date = "2016-01-01", end_date = "2049-12-31"
TCall - field: id_call = 1, id_period = 1000
The period is a relation between TPerson and TPeriod, in this example John has a mobile between "2016-01-01" and "2049-12-31". On the table TCall there are John's calls record, but if i replace the period (TPeriod table) end_date to "2016-02-01", from my understanding the end_date will be inconsistent, it turns out i cann't replace because it's a value object, not a entity. I considered to implement like this.
// Create a class DatePeriod
public class DatePeriod {
private final begin_date;
private final end_date;
DatePeriod() {}
public static DatePeriod of(Date begin_date, Date end_date) {
this.begin_date = begin_date;
this.end_date = end_date;
}
// implement equals / hashcode...
}
// Period class
public class Period {
int id;
// others mappings id_person / id_mobile
DatePeriod datePeriod;
}
Still, i will have to update datePeriod attribute
Thank you for your attention to this matter

How do I flatten a hierarchy in LINQ to Entities?

I have a class Org, which has ParentId (which points to a Consumer) and Orgs properties, to enable a hierarchy of Org instances. I also have a class Customer, which has a OrgId property. Given any Org instance, named Owner, how can I retrieve all Customer instances for that org? That is, before LINQ I would do a 'manual' traversal of the Org tree with Owner as its root. I'm sure something simpler exists though.
Example: If I have a root level Org called 'Film', with Id '1', and sub-Org called 'Horror' with ParentId of '1', and Id of 23, I want to query for all Customers under Film, so I must get all customers with OrgId's of both 1 and 23.
Linq won't help you with this but SQL Server will.
Create a CTE to generate a flattened list of Org Ids, something like:
CREATE PROCEDURE [dbo].[OrganizationIds]
#rootId int
AS
WITH OrgCte AS
(
SELECT OrganizationId FROM Organizations where OrganizationId = #rootId
UNION ALL
SELECT parent.OrganizationId FROM Organizations parent
INNER JOIN OrgCte child ON parent.Parent_OrganizationId = Child.OrganizationId
)
SELECT * FROM OrgCte
RETURN 0
Now add a function import to your context mapped to this stored procedure. This results in a method on your context (the returned values are nullable int since the original Parent_OrganizationId is declared as INT NULL):
public partial class TestEntities : ObjectContext
{
public ObjectResult<int?> OrganizationIds(int? rootId)
{
...
Now you can use a query like this:
// get all org ids for specific root. This needs to be a separate
// query or LtoE throws an exception regarding nullable int.
var ids = OrganizationIds(2);
// now find all customers
Customers.Where (c => ids.Contains(c.Organization.OrganizationId)).Dump();
Unfortunately, not natively in Entity Framework. You need to build your own solution. Probably you need to iterate up to the root. You can optimize this algorithm by asking EF to get a certain number of parents in one go like this:
...
select new { x.Customer, x.Parent.Customer, x.Parent.Parent.Customer }
You are limited to a statically fixed number of parent with this approach (here: 3), but it will save you 2/3 of the database roundtrips.
Edit: I think I did not get your data model right but I hope the idea is clear.
Edit 2: In response to your comment and edit I have adapted the approach like this:
var rootOrg = ...;
var orgLevels = new [] {
select o from db.Orgs where o == rootOrg, //level 0
select o from db.Orgs where o.ParentOrg == rootOrg, //level 1
select o from db.Orgs where o.ParentOrg.ParentOrg == rootOrg, //level 2
select o from db.Orgs where o.ParentOrg.ParentOrg.ParentOrg == rootOrg, //level 3
};
var setOfAllOrgsInSubtree = orgLevels.Aggregate((a, b) => a.Union(b)); //query for all org levels
var customers = from c in db.Customers where setOfAllOrgsInSubtree.Contains(c.Org) select c;
Notice that this only works for a bounded maximum tree depth. In practice, this is usually the case (like 10 or 20).
Performance will not be great but it is a LINQ-to-Entities-only solution.

Simple Linq-to-entities query involving .Include I believe

I have a Linq-to-Entities query that is not complicated but requires an .include and/or projection and/or join because it must be executed in one pass.
Here is my database (Microsoft SQL Server 2008):
Table A (Customers) (contains CustomerID (customer IDs), and ZipCode (zip codes) as strings.
Table C (Categories) (contains CategoryID (categories) like "food", "shelter","clothing", "housing" (primary keys).
Table A_C is a linking table, since Tables A and C are linked as many-to-many: contains just two fields: CustomerID "customer IDs" and CategoryID (Categories), in combination as primary keys. This table is a linking table betweeen tables A and C.
Here is my query, that must be executed in just one trip to the database: I need to select all records in Table A that satisfy a condition, then filter these records depending on a 'list of parameters' that are found in the linking Table A_C--and do this all in one trip to the database. But I don't know what the length or composition of the list of parameters for Table A_C is, ahead of time--it varies from call to call. Thus this list of parameters varies method call by method call.
To give a more concrete example:
Table A has a list of customer IDs. I find the customers that live in a certain Zip code. Then, in the same SQL query, I need to find which of these customers have selected certain categories: Food, Clothing, Housing, etc, but my web method does not know ahead of time what these categories are, rather, they are passed as a list to the method: List myCategoryList (which could be 1 category or 100 categories, and varies method call by method call).
How do I write the projection using Linq-to-Entities? When the list of parameters varies? And do it all in one pass?
List<string> CategoryList = new List<string>() { "Food", "Shelter", "Housing" }; // in one call to the web service method
List<string> CategoryList = new List<string>() { "Food", "Clothing" }; //could be a second call--it varies and I don't know ahead of time what the List will be
So how can I do the SQL query using Linq-to-Entities? In one pass? (Of course I could loop through the list, and make repeated trips to the database, but that's not an optimal solution I am told). Projection,.Include are keywords but surfing the net yielded nothing.
Here is a crude guess, just to get ball rolling:
public void WebMethod1 (CategoryList)
{
using (EntityFramework1 context = new EntityFramework1())
{
/* assume CategoryList is a list of strings passed into the method and is,for this particular call,something like: List<string> CategoryList = new List<string>() { "Food", "Clothing" }; for this call, but in the next call it could be: List<string> CategoryList = new List<string>() { "Food", "Shelter", "Housing" } */
string ZipCodeString = "12345";
string customerIDString = "E12RJ55";
var CustomersFromZipCodeHavingSelectedCertainCategories = from x in context.A_C
where x.A.CustomerID == customerIDString
where x.A.StartsWith(ZipCodeString)
where x.A_C.Contains(CategoryList) //???? This is clearly not grammatical, but what is?
select x;
}
/*
my problem is: I want to filter all records from A that contain a zipcode 12345, and that also have a certain CustomerID "E12RJ55" from table A, but further filter this set with all such CustomerIDs in linking table A_C that contain the categories "Food" and "Clothing".
How to do this in one pass? I can do this quite easily in multiple passes and trips to the database using code, but somebody in this thread here http://bit.ly/rEG2AM suggested I do a Join/projection and do it all in one fell swoop.
*/
I will also accept SQL answers since it might help yield a solution. This question btw is not difficult I believe--but I could not find an answer on the net.
EDIT: with answer and credit to david s.
I thank you for the answer david.s. Here is what worked, slightly different than the answer by david.s, in that I am using the linking table (bridge table) called “Customer_Categories” that is between the table Customer and Categories and contains the primary key of each (as is required for many-to-many relationships). This bridge table is what I called "A_C" in my original answer, and here has ints rather than strings but is the same thing. Intellisense picked up this table and I used it, and it works. Also keep in mind that CategoryList is a list of ints, List CategoryList = new List();, yet amazingly it automagically works inside this SQL-to-Entities query:
Var CustomersFromZipCOde = context.Customers.Where (custo => custo.CustomerID==customerIDString && custo.ZipCode.StartsWith(ZipCodeString) && custo.Customer_Categories.Any(categ => CategoryList.Contains(categ.CategoryID)));
//gives the right output, incredible.
First of all i would like to say that even if you explanation is very long it is not very clear. You would like a simple Linq-to-Entities query but you don't give the Entities, you only speak of tables in your database.
Assuming you have the following entities:
public class Customer
{
public string CustomerID { get; set; }
public string ZipCode { get; set; }
public virtual ICollection<Category> Categories { get; set; }
}
public class Category
{
public string CategoryID { get; set; }
public virtual ICollection<Customer> Customers { get; set; }
}
Your query might look like this:
var CustomersFromZipCodeHavingSelectedCertainCategories =
context.Customers.Where(
customer => customer.CustomerID == customerIDString &&
customer.ZipCode.StartsWith(ZipCodeString) &&
customer.Categories.Any(
category => CategoryList.Contains(category.CategoryID));
More info on other ways to do this here:
http://smehrozalam.wordpress.com/2010/06/29/entity-framework-queries-involving-many-to-many-relationship-tables/

NHibernate sorting (SQL as a second option)

I'm using NHibernate as my ORM and I'm trying to sort some data. The data needs to be retrieved paged.
Two of the columns in my Request table are UrgencyID and CreateDate. UrgencyID is a FK to the Urgency table with static data:
1 = Low, 2 = Normal, 3 = High, 4 = Critical.
I need to order my Requests in the following manner.
Critical Requests by CreateDate descending
All other requests by CreateDate descending
So my list of Requests should always have Critical by CreateDate desc at the top and then all other Requests (disregarding UrgencyID) by CreateDate desc
Is it possible to perform this sort order in NHibernate (using the Criteria API)?
If not, how would I do this in SQL? In a stored procedure?
EDIT: Solution thanks to both #DanP and #Michael Pakhantsov
Using the this_ prefix in the sql string as this is the default NHibernate prefix for the primary table selection.
public class OperatorJobQueueOrder : Order
{
public OperatorJobQueueOrder() : base("", true) { }
public override NHibernate.SqlCommand.SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return new NHibernate.SqlCommand.SqlString("case this_.JobRequestUrgencyID when 4 then 4 else 0 end desc, this_.CreatedDate");
}
}
You may be able to create a custom sort order to handle this through the critiera api; see this question for an example implementation.
IN SQL ORDER BY will be
ORDER by case UrgencyId when 4 then 4 else 0 end, CreateDate desc

How do you bring Denormalized Values Into your Business Objects?

I have two Tables.
Order - With Columns OrderID, OrderStatusID
OrderStatus - With Columns OrderStatusID, Description
I have an Order Object which calls to the database and fills its properties for use in my code. Right now I have access to Order.OrderStatusID, but in my application I really need access to the "Description" field.
How do you handle this elegantly with good OO design?
Usually I prefer to handle lookups as Value objects. I also use Null Object pattern.
public class Order {
private int statusID;
public OrderStatus Status {
get {
return OrderStatus.Resolve(statusID);
}
set {
statusID = value != null ? value.ID : null;
}
}
}
public class OrderStatus {
public static OrderStatus Resolve(int statusID)
{
OrderStatus status = null;
// read from cache or DB
...
// if not found return Null object
if (status == null)
status = new OrderStatus(null, string.Empty);
return status;
}
}
The system I'm currently working with creates an instance of the other business object and sets the Id. The other business object is then retrieved when it is used. e.g.
Order Properties
int OrderId = 5
int OrderStatusId = 3
OrderStatus OrderStatus_ref
{
get
{
if OrderStatus_ref == null
OrderStatus_ref = new OrderStatus(OrderStatusId)
return OrderStatus_ref
}
}
That's the general idea anyways.
You can use a SQL select statement with a Join to the OrderStatus table, and include the columns yo want from each table ...
Select O.OrderId, O.OrderStatusId, S.Descriptiuon
From Order O
Join OrderStatus S
On S.OrderStatusId = O.OrderStatusId
Where OrderId = 23 -- or whatever
Is it a one-to-one relationship between Order and OrderStatus? I guess it depends on the purpose to why you would have an OrderStatus table as I would argue that there isnt actually any need for a separate OrderStatus table?
Basically all that table gives you is the ability to change the description of the order status. From within code, you would then be writing code according to either a predefined OrderStatusID (from seed data?) or via the description. If this is the case then why not have the Order table contain an OrderStatus column which is an integer and that can map to an enum type?
My Order object would probably include the status description field (readonly [to non internal classes]), as well as any other similar fields.
Under the hood my getters (e.g. LoadByID, LoadAll, etc) would probably use a View (e.g. OrdersView) that contains all of those descriptive fields. Those description fields are readonly so that you don't accidentally set those fields thinking that you can save the changes to the database.