I have a database that has a one-to-one relationship modeled between a Person and a Address (that uses person id). However, I cannot find a way to make the map using NHibernate.
My table structure is the following:
PersonTable
PersonId
PersonName
PersonAge
AddressTable
PersonId
CountryName
StreetName
StateName
And I would like to have something like this as the final class:
PersonClass
int Id
string Name
int Age
Address HomeAddress
AddressClass
string Street
string Country
string State
Person Owner
I tried with HasOne relationship but I couldn´t reuse PersonId as Address Identifier.
Thanks!
Edit: I forgot to mention that I´m using FluentNHibernate so both fluent mapping and XML will be fine.
The problem is that your database schema does not represent a "Has One" relationship between Person and Address. It represents a "Has Many" relationship; You may be artificially limiting it to be one address per person, but that doesn't change the fact that the model is multiple addresses per person.
To get a "Has One" relationship, you would put the AddressID on the the PersonTable.
I did it using Id().GeneratedBy.Foreign() in Address class map referencing it to the Person´s ID and it worked.
Thanks!
I would map it as a component of Person. In the person ClassMap add the following:
Component(x => x.Address, m =>
{
m.Map(x => x.Street, "Street");
m.Map(x => x.State, "State");
// more here
});
Cheers
Related
I have a Entity Contact which has three joined-subclass (Person, Company, Branch).
When I do a select-query on Contact where I should only get the Person's, Companies or Branches, I can do
select from Contact a where a.class = Person
this is working correct in the case of Person and Branch. But because Branch is himself referencing Company (with CompanyId), and when I do now
select from Contact a where a.class = Company
it will replace Company with CompanyId (from the Branch-Entity).
Does someone have an Idea, how I can prevent HQL from replacing the class-value with a real column?
Try to use fully qualified name of the class (including the namespace):
select from Contact a where a.class = Your.Namespace.Company
This should help NHibernate to differentiate class name from property name.
I have one situation given below :
Each student can enrolled into more than one class.
Each class can accommodate more than one student.
which of the following is possible answer :
(1) 1 to N
(2) M to N to 1
(3) M to N
(4) Anything else
if answer is (4) than which other answer is possible ......
any comments appreciable,
thnks in advance, Milan Mendpara
It's M:N.
Look at the problem from both entity's perspective to find the answer.
Each class can have many student entities. So we have 1:M.
Each student can be enrolled in many class. So that's 1:M as well.
In a normalized database you'd have Class and Student defined (minimally) like this:
Class: Id, Name
Student: Id, FirstName, LastName
If you add a foreign key on Class to Student you're only allowing each Class to have a single Student. If you put the foreign key on Student to Class you're only allowing each Student to take one Class at a time. The answer is to use an association table as this is an M:N relationship:
StudentClass: StudentId, ClassId
Hope that helps.
It's number 3.
Multiple students (M) call enroll in multiple classes (N).
The answer is
3 M to N
You need to define a table with fields class_id and student_id to store the relations.
Check out this article about database normalization
http://en.wikipedia.org/wiki/Database_normalization
i am facing problem to fetch out records from table using Yii relationship,
i have 3 tables
1) Students -> ID, Name, Roll_Number
2) Subjects -> ID, Name
3) Students_taken_Subjects -> ID, Student_ID, Subject_ID
Suppose there are number of students have taken more than one subjects which are stored in the 3rd table "Students_taken_Subjects" then how i can fetch out the list of students taken any specific subject?
e.g. list of students taken maths
which one from below relationships are correct and how can i get results into the $dataProvider variable?
'Students'=>array(self::HAS_MANY, 'Subjects', 'Student_ID'),
and
return array(
'Students'=>array(self::MANY_MANY, 'Subjects',
'Students_taken_Subjects(student_id, subject_id)'),
);
The relationship between Subjects and Students is MANY_MANY, but you've written it a bit wrong, This is what you need:
class Subjects extends CActiveRecord
{
// ...
public function relations()
{
return array(
'Students'=>array(self::MANY_MANY, 'Students', 'Students_taken_Subjects(Subject_ID, Student_ID)'),
);
}
// ...
}
Once you've written this relation, the Subjects active record will have a Students property that returns an array with the 0 or more students taking that subject. You can access them like this:
$subject = Subjects::model()->findByPk($pk);
$students = $subject->Students; // an array with the subject's students
The above code will result in two DB accesses, one for the $subject and one for the related $students. This might be fine, but if you are accessing a lot of subjects it could become a problem with too much "lazy loading". You can tell Yii to "eager load" the students along with the subjects like this:
$subjects = Subjects::model()->with('Students')->findAll();
Here you are finding all of the subjects, but alerting Yii--using with('Students')--that you'll be wanting each subject's student information as well. This ensures that all of the students related to the subjects you find will be grabbed at once. An alternative to the with() function is to use a criteria's with property:
$criteria=new CDbCriteria;
$criteria->with = array('Students');
$subjects = Subjects::model()->findAll($criteria);
Either way, when you do ask for a subject's students like this:
$subjects[0]->Students;
$subjects[1]->Students;
// ...
you will not get another DB call each time because Yii already loaded the data.
You'll need to provide more details about what you are wanting to do with the students in the data provider before I can give any more details about that.
Help me translate this into proper NHibernate...
I have an Oracle database with 2 tables:
Employees:
Id (unique id)
FirstName (string)
LastName (string)
Location (string)
Locations:
Name (string)
Address (string)
As you can see the Employees table has a unique id, but the Locations table has no id whatsoever. The Name field is a regular field and is not unique.
In Oracle SQL I can run the following query:
SELECT *
FROM Employees e
LEFT OUTER JOIN Locations l
ON e.Location = l.Name
WHERE e.Id = 42
The location where the employee 42 is, has 2 rows in the Locations table, so this query returns 2 rows, one for each location found for employee 42.
Well, I can't figure out how to translate this into an NHibernate mapping + query (I use Fluent NHibernate). I tend to think that I should map Employees.Location as a Reference to Locations.Name, and so when running my HQL query it should return 2 objects, but NHibernate wouldn't let me retrieve a list from a Reference. So I tried HasMany but it doesn't work either, because NHibernate wants a field in Locations referring back to Employees, which kinda makes sense.
My HQL query looks like this:
select e
from Employees e
left join e.Locations l
where e.SGId like :sgId
Why can I do this in regular SQL and not in NHibernate?
Thanks.
I found the solution, you have to use HasMany(x => x.Locations) in conjunction with .PropertyRef("Location") so that hibernate knows that the field in Employee to be used for the join should be Location (and not the id of employee as is the default).
class Employee
{
public virtual int Id {get;set}
public virtual string FirstName {get;set;}
public virtual string LastName {get;set;}
public virtual string Location {get;set;}
public virtual IList<Location> Locations {get;set;}
}
class EmployeeMapping : ClassMap<Employee>
{
public EmployeeMapping()
{
Id(x=>x.Id);
Map(x=>x.FirstName);
Map(x=>x.LastName);
Map(x=>x.Location);
HasMany<Location>(x => x.Locations)
.PropertyRef("Location")
.KeyColumn("Name");
}
}
Also I found a few flaws in my approach due mainly to the weird legacy database I'm working with. That doesn't change the solution but I want to add that if one of the tables you're dealing with doesn't have unique ids, you're in trouble. Hibernate needs a unique id, so in my case I had to come up with a composite id made from multiple fields in order to make it unique. This is another debate but I wanted to mention it here to help whoever is researching this topic in the future.
For you mapping you need to use a collection/array/list/set object and a HasMany on your employees mapping for the location if it is going to return 2 locations for the one employee
class Employee
{
public virtual int Id {get;set}
public virtual string FirstName {get;set;}
public virtual string LastName {get;set;}
public virtual IList<Location> Location {get;set;}
}
class EmployeeMapping : ClassMap<Employee>
{
public EmployeeMapping()
{
Id(x=>x.Id);
Map(x=>x.FirstName);
Map(x=>x.LastName);
HasMany<Location>(x => x.Location)
.KeyColumn("Name")
.PropertyRef("Location")
.LazyLoad();
}
}
I'm trying to map two classes together via a N:N relationship, and that's working fine as is. However, there's a field in my join table that I'd like to also map to a property on the child object, and I haven't an inkling on how to do that.
Basically, I have my map done something like:
CompanyMap : ClassMap<Company> {
public CompanyMap() {
HasManyToMany<Employee>(x => x.Employees)
.Table("COMPANY_EMPLOYEE")
.ParentKeyColumn("COMPANY_ID")
.ChildKeyColumn("EMPLOYEE_ID")
;
}
}
with my Employee class having a .Tenure property.
The value of that tenure is specified in my COMPANY_EMPLOYEE join table, with the following schema:
COMPANY_ID | EMPLOYEE_ID | TENURE
I don't know if this is something embarassingly simple, or something downright impossible to do, but if someone can point me in the right direction, I'd really appreciate it.
Thanks!
You need to create a CompanyEmployee object in your domain model and map both relationships to it as one-to-many. That is, Company has a collection of CompanyEmployee and Employee has a collection of CompanyEmployee.