nhibernate: how to map two tables to a single non-persistent class? - class

I have two similar tables:
Table1:
[ id ] | [ name ]
Table2:
[ id ] | [ name ]
and I need to read/write data using only one class:
public class TwinTable
{
public virtual int Id { get; set; }
public virtual string Name1 { get; set; }
public virtual string Name2 { get; set; }
}
Plus one of the tables may or may not have an entity with the specified Id, and both tables may or may not have entities, so Name1 can be null and Name2 can be null and both of them can be null.
I can not change the structure of the DB, and it's not a good thing if i have to add something to it.
Hope for your help!

One solution is to map Table1 to a class, and then map Table2 as a joined-subclass of Table1. The joined subclass will then be like your TwinTable as you described above:
<class name="Class1" table="Table1" >
<id name="Id" column="id">
<generator class="identity" />
</id>
<property name="Name1" column="name" not-null="true" />
</class>
<joined-subclass name="Class2" table="Table2">
<key column="Id" />
<property name="Name2" column="name" not-null="true" />
</joined-subclass>

Related

Entity Framework: Add-Migration is removing the nullable:false (allowing null)

The migration believes email should now be nullable, and I can't see where it's coming up with this idea. The database before the migration is NOT NULL. Running Add-Migration produces the code changes below, where Email is now marked nullable; however, the [Required] attribute is present on the string and this code has been untouched for sometime. What are some other side-effects that could be causing this behavior? (Target is SQL server)
(1) Unchanged Model:
[Table("UserProfile")]
public class UserProfile
{
// .. snip...
[JsonProperty("email"), Required, Display(Name = "Email")]
public string Email { get; set; }
}
(2)
Add-Migration ExampleMigration
(3) Output migration:
public partial class ExampleMigration : DbMigration
{
public override void Up()
{
AlterColumn("dbo.UserProfile", "Email", c => c.String());
}
public override void Down()
{
AlterColumn("dbo.UserProfile", "Email", c => c.String(nullable: false));
}
}
Comparing resx migration schemas shows the same result, where the latest migration removes Nullable="false".
Before
<Property Name="Email" Type="String" MaxLength="Max" FixedLength="false" Unicode="true" Nullable="false" />
After
<Property Name="Email" Type="String" MaxLength="Max" FixedLength="false" Unicode="true" />
To work around this issue, I ran the migration, removed the incorrect lines from up/down, did a file compare against the prior and current migration decompressed 'target' value in the resx, took the changes I wanted, and recompressed the result and jammed it back in the resx.
Not ideal. Not recommended.

Evaluating object with List property

I try to evaluate this rule
<?xml version="1.0" encoding="utf-8"?>
<codeeffects
xmlns="http://codeeffects.com/schemas/rule/41"
xmlns:ui="http://codeeffects.com/schemas/ui/4">
<rule id="PerformCalculation" webrule="5.0.9.6" utc="2020-11-23T13:13:42.3010" type="domain_product.Configs.WorkflowEngine.MicroflowModel, domain-product, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" eval="false">
<definition>
<if>
<clause>
<rule id="40494eaf-4de0-4b3b-85b9-1c73473c2660" operator="doesNotExist">
<property name="e536c617_2636_47e8_93bb_66bb6c7fe3c0" />
</rule>
</clause>
<then>
<set>
<property name="775e6e9c_154f_45b3_9360_3d0a154ee19d" />
<value>test1</value>
</set>
</then>
</if>
</definition>
<format>
<lines />
</format>
</rule>
<rule id="40494eaf-4de0-4b3b-85b9-1c73473c2660" webrule="5.0.9.6" utc="2020-11-23T13:13:42.3010" type="transformify_template_api_factory_product.Domain.Model_cb958c7f_3681_40c5_573c_08d88fb1664f, DynamicAssembly.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" eval="true">
<definition>
<condition type="equal">
<property name="Godini" />
<value type="numeric">50</value>
</condition>
</definition>
<format>
<lines />
</format>
</rule>
</codeeffects>
The classes are
public class Model_710e265b_d07c_4c1b_573d_08d88fb1664f
{
[Field(DisplayName = "Ime")]
public string Ime { get; set; }
[Field(DisplayName = "Prezime")]
public string Prezime { get; set; }
[Field(DisplayName = "Godini")]
public int Godini { get; set; }
}
public class MicroflowModel
{
[Field(DisplayName = "Variables -> Persons")]
public List<Model_710e265b_d07c_4c1b_573d_08d88fb1664f> e536c617_2636_47e8_93bb_66bb6c7fe3c0{ get; set; }
[Field(DisplayName = "Variables -> var1")]
public string 775e6e9c_154f_45b3_9360_3d0a154ee19d { get; set; }
}
The class Model_710e265b_d07c_4c1b_573d_08d88fb1664f is a part of an assembly called 'DynamicAssembly.dll' that is not loaded into the app-domain, but the class exists.
The class MicroflowModel is a part of a dynamically created assembly, and is generated with TypeBuilder.
When evaluating objects without List properties, the evaluation process is ok.
When evaluating objects with lists from the 'DynamicAssembly.dll' assembly (like in the example), the Evaluator constructor fails with this Message:
Value cannot be null. (Parameter 'type')
and StackTrace:
at System.Linq.Expressions.Expression.Validate(Type type, Boolean allowByRef)
at System.Linq.Expressions.Expression.Parameter(Type type, String name)
at CodeEffects.Rule.Core.ExpressionBuilderBase.BuildRule(XElement element)
at CodeEffects.Rule.Core.ExpressionBuilderBase.Build(XElement element)
at CodeEffects.Rule.Core.ExpressionBuilderBase.BuildIfRule(XElement element)
at CodeEffects.Rule.Core.ExpressionBuilderBase.Build(XElement element)
at CodeEffects.Rule.Core.ExpressionBuilderBase.Build(IEnumerable`1 elements)
at CodeEffects.Rule.Core.ExpressionBuilderBase.GetSafeExpressionBody(XElement rule, Boolean addSourceNullCheck)
at CodeEffects.Rule.Core.ExpressionBuilder.GetPredicateExpression(XElement rule)
at CodeEffects.Rule.Core.Evaluator.CompileRule(XElement rule)
at CodeEffects.Rule.Core.EvaluatorBase..ctor(Type sourceType, String rulesetXml, EvaluationParameters parameters, IFlexDataProvider provider)
at CodeEffects.Rule.Core.Evaluator..ctor(Type sourceType, String rulesetXml, EvaluationParameters parameters)
at ...
Please help
You need to make that class available. The ExpressionBuilder must be able to load the type referenced in the internal rule (id="40494eaf-4de0-4b3b-85b9-1c73473c2660") using Type.GetType(), so as to build an expression tree.
Internally it calls
Type ruleType = Type.GetType("transformify_template_api_factory_product.Domain.Model_cb958c7f_3681_40c5_573c_08d88fb1664f, DynamicAssembly.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");
Since it can't find it, the result is null and the next call to Expression.Parameter() fails.

LookupField with one-to-many relationship

I want to show in my document a one-to-many relationship- a simple drop-down list with values. For that, I trying to create and configure LookupField component by using Cuba platform.
I have two entities:
CardItem:
#NamePattern("The document in the following state: %s|cardState")
#Table(name = "TKB_CARD_ITEM")
#Entity(name = "tkb$CardItem")
public class CardItem extends StandardEntity {
// skipped
CardType:
#NamePattern("CardType: %s, %s |cardTypeItem, cardTypeName")
#Table(name = "TKB_CARD_TYPE")
#Entity(name = "tkb$CardType")
public class CardType extends StandardEntity {
#OneToMany(targetEntity=CardItem.class )
private List<CardItem> cardItems;
// skipped
In my card-item-edit.xml I have the following:
<dsContext>
<datasource id="CardItemDs" class="com.company.tkb.entity.CardItem" view="_local"/>
<collectionDatasource id="CardTypeDs" class="com.company.tkb.entity.CardType" view="_local">
<query>select c from tkb$CardType c</query>
</collectionDatasource>
</dsContext>
<layout>
<lookupField datasource="CardItemDs" property="cardTypeName" optionsDatasource="CardTypeDs"/>
I filled the table TKB_CARD_TYPE with some values. Now I'm trying to get a drop-down list with values when I create CardItem, but the list is empty.
What could be the problem?
I would be very grateful for the information. Thanks to all.
What helped:
In CardItemEdit class I added the following:
public class CardItemEdit extends AbstractEditor<CardItem> {
#Inject
private Datasource<CardItem> cardItemDs;
#Inject
private Metadata metadata;
#Override
public void init(Map<String, Object> params) {
CardItem cardItem = metadata.create(CardItem.class);
cardItemDs.setItem(cardItem);
}
}
Then I changed the direction of the relationship: part of my CardItem entity:
#NamePattern("The document in the following state: %s|cardState")
#Table(name = "TKB_CARD_ITEM")
#Entity(name = "tkb$CardItem")
public class CardItem extends StandardEntity {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CARD_TYPE_ID")
protected CardType cardType;
// skipped
Part of my CardType entity:
#NamePattern("Тип входящего документа: %s | cardTypeName")
#Table(name = "TKB_CARD_TYPE")
#Entity(name = "tkb$CardType")
public class CardType extends StandardEntity {
// skipped
I defined the dsContext and lookupField by this way:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
caption="msg://editCaption"
class="com.tkbbank.client.web.item.CardItemEdit"
datasource="cardItemDs"
focusComponent="fieldGroup"
messagesPack="com.tkbbank.client.web.item">
<dsContext>
<datasource id="cardItemDs" class="com.tkbbank.client.entity.CardItem" allowCommit="false"/>
<collectionDatasource id="cardTypeDs" class="com.tkbbank.client.entity.CardType" view="_local">
<query>
<![CDATA[select e from demo$CardType e]]>
</query>
</collectionDatasource>
</dsContext>
<dialogMode forceDialog="true" width="AUTO"/>
<layout expand="windowActions" spacing="true">
<fieldGroup id="fieldGroup" datasource="cardItemDs">
<column width="500px">
<field id="cardCreationDate" editable="false"/>
<field id="cardType" caption="Тип документа">
<lookupField datasource="cardItemDs" property="cardType" optionsDatasource="cardTypeDs"/>
</field>
<field id="cardSubtype"/>
<field id="cardAutoFill"/>
<field id="cardOutcomeNumber"/>
<field id="cardDate"/>
<field id="cardOrganization"/>
<field id="cardDeliveryMethod"/>
<field id="cardAdditionalInformation"/>
<field id="registratorName"/>
</column>
</fieldGroup>
<frame id="windowActions" screen="editWindowActions"/>
</layout>
</window>
What I see now. My card:
Interface for populating CardType with data:
Interface viewing all the documents:
Now everything is ok.
By side: very helpfull questions about "Can’t find getter for property" exception(this error is appeared also):
Hibernate - PropertyNotFoundException: Could not find a getter for
“ Could not find a getter for ” Error
What is the purpose of AccessType.FIELD, AccessType.PROPERTY and #Access
IllegalArgumentException: Can’t find getter for property ” at class…, and forgetting to update #NamePattern

Object of type 'System.String' cannot be converted to type 'MongoDB.Bson.ObjectId'

I have a C# class which has an id field of type ObjectId:
[BsonId]
[SolrUniqueKey("id")]
public ObjectId Id { get; set; }
In Solr, the schema has defined id as:
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
When attempting to pull an object from Solr it fails because it can't cast the string id to MongoDB ObjectId. Does anyone an easy was of fixing this without changing the source for SolrNet?
For anyone interested, below is how I ended-up doing it without modifying SolrNet source code.
I've added an additional property in the class called IdAsString and set it as "BsonIgnore" so that it doesn't get stored in MongoDB, however I use that field to map it to Solr's id field:
[BsonId]
public ObjectId Id { get; set; }
[BsonIgnore]
[SolrUniqueKey("id")]
public string IdAsString
{
get { return Id.ToString(); }
set { Id = ObjectId.Parse(value); }
}

odata breeze: Collection of ComplexType: - "TypeError: Cannot call method '_createInstanceCore…"

I would like to use Breeze to work with an OData Service. I spent hours trying to get this running, but I did not find a solution, so I really hope anybody can help!? (I just started to use breeze - so I am sorry if I am missing something "obvious" here.)
What I would like to do is to use a Collection of sub-objects (ComplexType). I.e. I would like my entity class to have a collection property like this:
public List<Address> addresses { get; set; }
(Address is no entity which is persisted on its own in a DB collection, but a simple class with some properties (ComplexType))
The server is a MVC4 WebAPI ODATA Service that is based on Entity Framework Code First POCO classes that are persisted in a MongoDB database.
In the browser I get the following error, when the breeze library tries to read the ODATA metadata from the server (it does not even query the example collection, it has an error before that):
[Q] Unhandled rejection reasons (should be empty):
["TypeError: Cannot call method '_createInstanceCore…://localhost:56936/scripts/breeze.debug.js:236:26"]
Is there any way to get this running?
Thank you!
My client code looks like this:
var serverAddress = "http://localhost:56936/odata";
breeze.config.initializeAdapterInstances({ dataService: "OData" });
var manager = new breeze.EntityManager(serverAddress);
var query = breeze.EntityQuery.from("BreezeExample");
manager.executeQuery(query).then(querysucceeded).fail(queryfailed);
function querysucceeded(data) {
console.log("querysucceeded");
data.results.forEach(function (item) {
//...
});
}
function queryfailed(e) {
console.log("!!! queryfailed");
console.log(e);
}
The Model is as follows:
[BsonIgnoreExtraElements]
public class ExampleClass : MongoEntity
{
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string loginEmail { get; set; }
public bool? active { get; set; }
public ICollection<Address> addresses { get; set; } //THIS DOES NOT WORK CLIENT SIDE - WHY?
}
public class Address
{
public string place { get; set; }
public string street { get; set; }
public string houseNumber { get; set; }
public string postalCode { get; set; }
}
If I query the ODATA metadata using the browser (http://localhost:56936/odata/$metadata), I get this result:
<edmx:Edmx xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx" Version="1.0">
<edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="3.0" m:MaxDataServiceVersion="3.0">
<Schema xmlns="http://schemas.microsoft.com/ado/2009/11/edm" Namespace="MvcWebRole1.Models.MongoDB.Entities">
<EntityType Name="ExampleClass">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="loginEmail" Type="Edm.String" />
<Property Name="active" Type="Edm.Boolean" />
<Property Name="addresses" Type="Collection(MvcWebRole1.Models.MongoDB.Entities.Address)" Nullable="false" />
<Property Name="Id" Type="Edm.String" Nullable="false" />
</EntityType>
<ComplexType Name="Address">
<Property Name="place" Type="Edm.String" />
<Property Name="street" Type="Edm.String" />
<Property Name="houseNumber" Type="Edm.String" />
<Property Name="postalCode" Type="Edm.String" />
</ComplexType>
<EntityContainer Name="Container" m:IsDefaultEntityContainer="true">
<EntitySet Name="BreezeExample" EntityType="MvcWebRole1.Models.MongoDB.Entities.ExampleClass" />
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
If I query the BreezeExample collection (http://localhost:56936/odata/BreezeExample) I get this:
{
odata.metadata: "http://localhost:56936/odata/$metadata#BreezeExample",
value: [
{
loginEmail: "loginEmail1",
active: true,
addresses: [
{
place: "place",
street: "street",
houseNumber: "77",
postalCode: "123"
},
{
place: "place2",
street: "street",
houseNumber: "77",
postalCode: "123"
}
],
Id: "1"
},
{
loginEmail: "loginEmail2",
active: true,
addresses: [
{
place: "place",
street: "street",
houseNumber: "77",
postalCode: "123"
},
{
place: "place",
street: "street",
houseNumber: "77",
postalCode: "123"
}
],
Id: "2"
}
]
}
I managed to partially fix the problem by doing the following:
First of all, it turns out that Breeze doesn't understand the Collection(MvcWebRole1.Models.MongoDB.Entities.Address) type; So it cannot create the appropriate dataType property. This might be the reason while you get the error.
I changed the type to something like Edm.Self.Address.
The other change that I made was in the parseCsdlComplexProperty function. I added one more line which fixed everything.
var dp = new DataProperty({
nameOnServer: csdlProperty.name,
complexTypeName: complexTypeName,
isScalar: csdlProperty.isScalar, // LINE ADDED
isNullable: false
});
Just to recap, my metada file contains the following snippet
{
"name": "ColourByType",
"key": {
"propertyRef": {
"name": "Id"
}
},
"property": [
{
"name": "Id",
"type": "Edm.Int32",
"nullable": "false",
"annotation:StoreGeneratedPattern": "Identity"
},
{
"name": "Options", // This is the list that holds the instance of my complex type
"type": "Edm.Self.ColourByOption", // This is the complex type that is stored in the list
"isScalar": false
}
]
}
I'm sure that this solution is not ideal, but it worked for me.
I've asked a similar question; so you might want to keep on eye on it, as well
https://stackoverflow.com/questions/21258015/breezejs-metadata-is-missing-information-about-complex-properties