NHibernate 3.2 Mapping by code - can you map to private fields for Id and bag? - nhibernate-mapping

e.g.
this.Bag(
r => "privatefieldtomap",
map =>
{
map.Access(Access.Field);
map.Table("table");
map.Key(k => k.Column("foreignkey"));
},
r => r.Element(m => m.Column("columntomap")));
public SomeType()
{
this.Id(p => "privateidfield", Access(Access.Field));
this.Table("SomeTable");
this.Property(p => p.SomeProperty);
}
both throw an exception "expression expected; constant found"
We could do this using xml mapping.

Answer here https://groups.google.com/forum/#!topic/nhusers/wiH1DPGOhgU turns out there is an overload that accepts a string as first parameter whereas I was using a lambda expression.

Related

rbac authorization check in Yii doesn't work (Getting unknown property: app\models\Post::createdBy)

I looked at the documentation for rbac in Yii and thought I understood how it worked until I actually tried it.
This is the rule for checking whether the author of the post is trying to get the authorization for an action:
class AuthorRule extends Rule
{
public $name = 'isAuthor';
/**
* #param string|integer $user the user ID.
* #param Item $item the role or permission that this rule is associated with
* #param array $params parameters passed to ManagerInterface::checkAccess().
* #return boolean a value indicating whether the rule permits the role or permission it is associated with.
*/
public function execute($user, $item, $params)
{
return isset($params['model']) ? $params['model']->createdBy == $user : false;
}
}
This is how I am trying to use the rule and Yii's rbac:
public function actionUpdate($id)
{
$model = $this->findModel($id);
if (\Yii::$app->user->can('update', ['model' => $model])) {
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
}
However, I get this when I try to edit a Post:
Getting unknown property: app\models\Post::createdBy
So I thought I had to replace createdBy with userId which is a column in the table Post and I am getting a blank page meaning it doesn't work. So I am trying to guess what $user is.
I also tried:
return isset($params['model']) ? $params['model']->userId == $user->id : false;
and I am getting: Trying to get property of non-object.
What should I do to make it work? The doc seemed to suggest you just had to plug the conditional inside the controller action to make it work, but it doesn't seem to be the case at all.
var dump:
object(app\models\Post)[75]
private '_attributes' (yii\db\BaseActiveRecord) =>
array (size=6)
'id' => int 1
'userId' => int 1
'title' => string 'test' (length=4)
'content' => string 'lol' (length=3)
'dateCreated' => null
'dateUpdated' => null
private '_oldAttributes' (yii\db\BaseActiveRecord) =>
array (size=6)
'id' => int 1
'userId' => int 1
'title' => string 'test' (length=4)
'content' => string 'lol' (length=3)
'dateCreated' => null
'dateUpdated' => null
private '_related' (yii\db\BaseActiveRecord) =>
array (size=0)
empty
private '_errors' (yii\base\Model) => null
private '_validators' (yii\base\Model) => null
private '_scenario' (yii\base\Model) => string 'default' (length=7)
private '_events' (yii\base\Component) =>
array (size=0)
empty
private '_behaviors' (yii\base\Component) =>
array (size=0)
empty
null
The first error says, that you don't have a createdBy property in your Post model. Do you?
The second error is about trying to get a property of non-object variable. Could you show var_dump($params['model']); var_dump($user); before the return?

nhibernate doing eager fetch by default

i am using nhibenate by code mappings. for some reason it is doing eager fetching by default, whereas it should be lazy.
below is the mapping i have:
public EntityMap()
{
Lazy(true);
Id(x => x.Id, map =>
{
map.Generator(Generators.GuidComb);
map.UnsavedValue("00000000-0000-0000-0000-000000000000");
});
}
so i tried to specify the lazy(true) in the base class, so that all the relationships are done with lazy loading.
i am also using mapping by convention, which is configured as below:
// foreign key convention (many2one side)
mapper.BeforeMapManyToOne += (insp, prop, map) => map.Lazy(LazyRelation.Proxy);
mapper.BeforeMapManyToOne += (insp, prop, map) => map.Fetch(FetchKind.Select);
// bag conventions (one2many side)
mapper.BeforeMapBag += (insp, prop, map) => map.Lazy(CollectionLazy.Lazy);
mapper.BeforeMapBag += (insp, prop, map) => map.Fetch(CollectionFetchMode.Select);
// set conventions (one2many side)
mapper.BeforeMapSet += (insp, prop, map) => map.Lazy(CollectionLazy.Lazy);
mapper.BeforeMapSet += (insp, prop, map) => map.Fetch(CollectionFetchMode.Select);
so i have tried all the settings to make it fetch lazy, but its still fetching eager..
below is the query i am using to load the data:
var session = SessionManager.GetCurrentSession();
return session.QueryOver<Customer>().List();
the one/many to many mapping is specified as below:
Bag(x => x.Customer, colmap => { }, map => map.OneToMany(x => { }));
ManyToOne(x => x.Orders, map => { map.NotNullable(true); });
please help!!!
all the settings mentioned above were added to make it lazy load, initially none of the settings where specified....

Loquacious Nhibernate and composedID foreign key

I have two classes that I'm trying to map in Loquacious Nhibernate.
The mapping is like the following
public class FooMap : ClassMapping<Foo>
{
Table("FooTableName");
ComposedId(compIDMapper =>
{
compIDMapper.Property(x => x.SomeInt, m => m.Column("SomeInt"));
compIDMapper.ManyToOne(x => x.SomeReference, m => m.Column("SomeReference"));
});
}
public class BarMap : ClassMapping<Bar>
{
Table("BarTableName");
Id(x => x.ID, m => m.Column("barID"));
ManyToOne(x => x.Foo, m => m.Columns( columnMapper =>
{
columnMapper.Name("SomeIntID"); //Both of these columns are in the BarTableName like they should be
columnMapper.Name("SomeReferenceID");
}));
}
But when the mappings are being built I get the following error:
Foreign key (FK554EAF2427B2CA28:BarTableName[SomeIntID])) must have same number of columns as the refe,renced primary key (FooTableName[SomeInt, SomeReference])
I'm not sure what I'm doing wrong, it looks like it should work, but I've been banging my head on this for awhile now and haven't gotten anywhere. Any ideas on what I'm doing wrong?
Finally figured this out, posting this for anyone else who comes along.
My problem was misunderstanding the columns mapper. What it is supposed to be is the following:
ManyToOne(x => x.Foo, m => m.Columns(new Action<IColumnMapper>[]
{
colMapper => colMapper.Name("SomeIntID"),
colMapper => colMapper.Name("SomeReferenceID")
}));
This solved the issue. Should have noticed it when I looked at the function signature, but I completely missed it.
And also another shorter way
ManyToOne(x => x.Foo, m => m.Columns(c=> c.Name("SomeIntID"),c => c.Name("SomeReferenceID")));

Mapping IDictionary<Entity, Component> with MappingByCode

How can I map IDictionary<Entity, Component>? I've done this way:
Map<GeneralResourceType, Quantity>(x => x.BookedResources,
c =>
{
c.Key(ck => ck.Column("ProposedAction"));
c.Table("BookedResources");
},
k => k.ManyToMany(key => key.Column("ResourceTypeId")),
r => r.Component(qc => QuantityMapping.Mapping()));
(where GeneralResourceType is a mapped Entity and Quantity is a ValueObject). But during the call of BuildSession() exception is thrown:
NHibernate.MappingException : An association from the table BookedResources refers to an unmapped class: {MyNamespace}.Quantity.
Seams like it tries to find ClassMapping for Quantity, while value part mapped as Component.
First variant:
Map component in separate class inherited from ComponentMapping generic class.
Map dictionary property as follows:
Map(x => x.BookedResources, c =>
{
//any options access, cascade etc
});
Second variant (inline):
Map(x => x.BookedResources, x =>
{
//any options access, cascade etc
},
x => x.Element(),
x => x.Component(c =>
{
c.Class<Quantity>();
c.Property(p => p.Amount);
c.Property(p => p.Unit);
// any other properties
}
));

NHibernate and JoinAlias throw exception

I have query in HQL which works good:
var x =_session.CreateQuery("SELECT r FROM NHFolder f JOIN f.DocumentComputedRights r WHERE f.Id = " + rightsHolder.Id + " AND r.OrganisationalUnit.Id=" + person.Id);
var right = x.UniqueResult<NHDocumentComputedRight>();
Basically I receive NHDocumentComputedRight instance.
I've tried to implement the same query in QueryOver. I did this:
var right = _session.QueryOver<NHFolder>().JoinAlias(b => b.DocumentComputedRights, () => cp).Where(h => h.Id == rightsHolder.Id && cp.OrganisationalUnit.Id == person.Id)
.Select(u => cp).List<NHDocumentComputedRight>();
But I get null reference exception.
How can I implement this query in QueryOver?
Update (added mappings) - NHibernate 3.2:
public class FolderMapping: ClassMapping<NHFolder>
{
public FolderMapping()
{
Table("Folders");
Id(x => x.Id, map =>
{
map.Generator(IdGeneratorSelector.CreateGenerator());
});
//more not important properties...
Set(x => x.DocumentComputedRights, v =>
{
v.Table("DocumentComputedRightsFolder");
v.Cascade(Cascade.All | Cascade.DeleteOrphans);
v.Fetch(CollectionFetchMode.Subselect);
v.Lazy(CollectionLazy.Lazy);
}, h => h.ManyToMany());
Version(x => x.Version, map => map.Generated(VersionGeneration.Never));
}
}
public class DocumentComputedRightMapping : ClassMapping<NHDocumentComputedRight>
{
public DocumentComputedRightMapping()
{
Table("DocumentComputedRights");
Id(x => x.Id, map =>
{
map.Generator(IdGeneratorSelector.CreateGenerator());
});
//more not important properties...
ManyToOne(x => x.OrganisationalUnit, map =>
{
map.Column("OrganisationalUnit");
map.NotNullable(false);
map.Cascade(Cascade.None);
});
}
}
public class OrganisationUnitMapping : ClassMapping<NHOrganisationalUnit>
{
public OrganisationUnitMapping()
{
Table("OrganisationalUnits");
Id(x => x.Id, map =>
{
map.Generator(IdGeneratorSelector.CreateGenerator());
});
//more not important properties...
}
}
Thanks
AFAIK criteria/queryOver can only return the entity it was created for (NHFolder in your example) or columns which are set to entity with aliastobean. you could do a correlated subquery instead.
var subquery = QueryOver.Of<NHFolder>()
.JoinAlias(b => b.DocumentComputedRights, () => cp)
.Where(h => h.Id == rightsHolder.Id && cp.OrganisationalUnit.Id == person.Id)
.Select(u => cp.Id);
var right = _session.QueryOver<NHDocumentComputedRight>()
.WithSubquery.Where(r => r.Id).Eq(subquery)
.SingleOrDefault<NHDocumentComputedRight>();
I think you have a problem with the select statement, have you tried something like this:
var right = _session.QueryOver<NHFolder>()
.JoinAlias(b => b.DocumentComputedRights, () => cp)
.Select(x => x.DocumentComputedRights)
.Where(h => h.Id == rightsHolder.Id && cp.OrganisationalUnit.Id == person.Id)
.List<NHDocumentComputedRight>();
This is what is working for me so it should work in you case as well.
I would guess that the main reason behind the problem is the lack of proper overload on the Select method. In reality you would like to write it like this:
.JoinAlias(b => b.DocumentComputedRights, () => cp)
.Select(() => cp)
but the Expression<Func<object>> is not there. Hopefully it's going to be included in the next version.