EF 4.1 Table-per-Hierarchy - entity-framework-4.1

I'm trying to implement a simple TPH example from http://msdn.microsoft.com/en-us/library/dd793152.aspx. I have two tables:
PERSON
[PersonID] [int] IDENTITY(1,1) NOT NULL,
[PersonTypeID] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,
[HourlyRate] [int] NULL
PersonType
[PersonTypeID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL
In EF designer, I follow the tutorial and create a new Entity called Employee and specify Person as the base type. Then move the HourlyRate property to Employee. In the Mapping Details window, I map the entity to the Person table and it properly maps HourlyRate property to the correct DB field. Then I set Person to abstract.
If I build it now without specifying a condition and a discriminator in the Employee entity, it builds fine. If I follow the tutorial and specify HourlyRate as the condition and use "Is" "Not Null" as the discriminator, it builds fine.
But I want to use PersonTypeID as the discriminator and an Employee should have a PersonTypeID of 1. So I select PersonTypeID as the the condition field, "=" as the operator, and 1 as the value. When I build, VS tells me the it's successful but also has something in the Error window.
Error 3032: Problem in mapping fragments starting at line
798:Condition member 'Person.PersonTypeID' with a condition other than
'IsNull=False' is mapped. Either remove the condition on
Person.PersonTypeID or remove it from the mapping.
I read in another article that I need to delete the PersonType navigation property in the Person Entity. So I tried that but still got the same error.
I thought I was able to get this to work before on another project but I'm not sure what changed for this one. The only thing different that I can think of is that I recently updated to EF 4.1.
This is what I have set up in the designer
Any suggestions are greatly appreciated!

I figured it out. Adding the PersonType entity to the designer threw everything off. The key was to delete the PersonType navigation property as well as the PersonTypeID property. But since I included the PersonType entity, deleting PersonTypeID broke the foreign key constraint.
By not including PersonType entity, I can delete PersonTypeID and everything compiles successfully.

Related

IS this redundent data?

I think I know the answer but I am not confident enough yet to just go with it.
I am thinking i have redundant info that can be fixed by just making a table for the the description . Below in my monster inserts i have 'mdesc' it has the same data that is in the dialogue inserts i just have it as 'intro'. Should i make a monster description table to hold a mdescid and and description? something like this
CREATE TABLE `mdesc`(
`mdescid` int(15) UNSIGNED NOT NULL,
`monsterdesc` varchar(50) NOT NULL
);
SO then i could just put the mdescid in both my dialogue table and the monsters table and get rid of the intro insert
--monster inserts
INSERT INTO monster(monsterid,monstername,monsterloc,mdesc,weaponval)values(1,dragon,11,'a dragon',1);
INSERT INTO monster(monsterid,monstername,monsterloc,mdesc,weaponval)values(2,spider,8,'a poisonus spider',2);
INSERT INTO monster(monsterid,monstername,monsterloc,mdesc,weaponval)values(3,wasps,7,'a swarm of wasps',3);
INSERT INTO monster(monsterid,monstername,monsterloc,mdesc,weaponval)values(4,enchantress,13,'a seductive enchantress',4);
INSERT INTO monster(monsterid,monstername,monsterloc,mdesc,weaponval)values(5,bellyfish,5,'a slimy belly fish',5);
-- dialogue inserts
INSERT INTO dialogue(monsterid,intro,attack,outcome1,outcome2,outcome3)
values(1,'"a dragon."','"you fight and,"','" kill it with your sword!"','"it kills and eats you."','" you both run away!"');
There's no reason to spread the info for one monster over three tables. That's called a one-to-one relationship, one row of a table relates to only row of another table, and vice versa. It's rarely useful.
What you could do is change dialogue to have the monster, situation, and text.
create table monster_dialogues (
monster_id integer not null
foreign key(monster_id) references monsters(id)
situation varchar(255) not null,
dialogue varchar(255) not null
unique(monster_id, situation)
)
This is a one-to-many relationship, each monster has many dialogues. This avoids having to add a new column every time you have a new situation.
And instead of reproducing the same basic text over and over, have a default in your code.
-- Note, avoid including formatting like quotes and conjunctions in your data.
-- It restricts how the data can be used.
-- Leave the formatting of dialogue into sentences to the application.
select coalesce(dialogue, 'you fight')
from monster_dialogues
where monster_id = ?
and situation = 'attack'
Note that using a database for this is probably overkill. Unless there's a very large number of monsters or you need to search through a large number of dialogues a simple JSON file would do.
{
"dragon": {
"damage": 100,
"health": 200,
"dialogues": {
"attack": "you fight",
}
}
}

Accessing a NULL related models in yii2

In yii2 view I am accessing property of related model like below
$objPatientModel->physicianUser->diallingCode->phonecode
To explain it :
I have foreign key physician_user in patient table and in patient table I have dialling code (id from another table -- Diallingcodes) and in diallingcodes table I have attribute phonecode .
Now my problem is if in case value is physician_user is NULL then this throws the errors like 'try to get property of non object' which is because $objPatientModel->physicianUser returns NULL instead of empty object .I want to know is there any class or method that can be overridden in yii2 so that above error can be avoided without placing the checks ?
Use ArrayHelper.
\yii\helpers\ArrayHelper::getValue($objPatientModel, 'physicianUser.diallingCode.phonecode', null);
It returns NULL in case value in physician_user is NULL
ArrayHelper api

Fluent NHibernate Schema output with errors when using list

I have two tables which are Many-To-One mapped. However, it is important to maintain the order of the second table, so when I use automapping, Fluent automapper creates a bag. I changed this to force a list by using this command:
.Override(Of ingredients)(Function(map) map.HasMany(Function(x) x.PolygonData).AsList())
(VB.NET syntax)
So I say "AsList" and instead of using a bag, the mapping xml which gets generated contains a list now. Fine so far. However,
the statement generated cannot be handled by MySQL. I use MySQL55Dialect to create the statements and I use exactly that version. But it creates the following create:
create table `ingredients` (
Id INTEGER NOT NULL AUTO_INCREMENT,
Name FLOAT,
Amout FLOAT,
Soup_id INTEGER,
Index INTEGER,
primary key (Id)
)
It crashes because of the line "Index INTEGER," but I don't know what to do here. Any ideas?
Thanks!!
Best,
Chris
I would suspect that Index could be a keyword for MySQL. To avoid such conflict, we can define different Index column name (sorry for C# notation)
HasMany(x => x.PolygonData)
.AsList(idx => idx.Column("indexColumnName").Type<int>())

Naming a multi-column constraint using JPA

The name attribute of #UniqueConstraint seems to have no effect.
#Entity
#Table(name = "TAG", uniqueConstraints = #UniqueConstraint(columnNames = {
"TAG_NAME", "USERS_ID" }, name="UQ_TAG_USER"))
public class Tag extends BaseEntity {
}
I'm usning SQL Server 2008, JPA 2.0 with Hibernate 3.6.
On the DB side an index, UQ__TAG__6EF57B66 is created instead of UQ_TAG_USER.
What am I missing? is there no way to enforce a given name from java side? and one must resort to editing schema files? we are a small shop without a DBA and I try to make do as much as I can by the help of hibernate schema facilities.
I assume you are using hibernate because you have it in the tags for this question. It's a bug/missing feature in hibernate:
https://hibernate.onjira.com/browse/HB-1245
It will simply ignore the unique constraint name when the dialect supports creating the constraint in the same statement as create table.
I've checked SqlServer and Oracle dialects and they both support this way of creating the constraint, that will cause the bug you are experiencing.
There are two ways to workaround this bug:
1. The quick way:
Just extend the dialect and return false for supportsUniqueConstraintInCreateAlterTable() method:
public static class SQLServerDialectImproved extends SQLServerDialect {
#Override
public boolean supportsUniqueConstraintInCreateAlterTable() {
return false;
}
}
And set this class as your dialect in hibernate.dialect property of the persistence unit configuration (persistence.xml).
2. The right way:
Fix the hibernate code and recompile:
The bug is at org.hibernate.mapping.UniqueKey class, the method sqlConstraintString() will return unique (TAG_NAME, USERS_ID) for all dialects, even if they support constraint UQ_TAG_USER unique (TAG_NAME, USERS_ID).
But that is probably a larger change (need to support all kinds of dialects, etc.)
Under the hood:
If you use the original dialect, it will cause the following sql statement to be executed to create the table (added id column):
create table TAG (
id bigint not null,
TAG_NAME varchar(255),
USERS_ID varchar(255),
primary key (id),
unique (TAG_NAME, USERS_ID)
)
And after you apply the fix as stated in first option the following sql statements will be executed:
create table TAG (
id numeric(19,0) not null,
TAG_NAME varchar(255),
USERS_ID varchar(255),
primary key (id)
)
create unique index UQ_TAG_USER on TAG (TAG_NAME, USERS_ID)
which include the creation of the unique constraint with the chosen name (UQ_TAG_USER) in a separate statement.

how to Search multiple columns of a table in MySQL?

Given a table named "person" (in a MySQL database/schema), kind of like this one:
code varchar(25)
lastname varchar(25)
firstname varchar(25)
I'm trying to make a stored function to receive "code" or a part of "code" (which of course, is the code that identifies that person) and return a 'list' of suggestions of persons that have a similar code.
What I'm not sure is how to search like in an auto complete kind of way, returning all possible results (or just five); and also how to return this "list" of persons from the stored procedure.
Any idea how I could do this?, Thanks!
You can use wild cards in SQL. Is this what you are looking for?
SELECT * FROM person WHERE code LIKE '%part_of_code%'