I have a problem with Entity Developer and model defined function. Ealier I was mapping functions as a stored procedures because Entity Developer has no support for database functions as it goes. I was using solution mentioned in this topic from devart forum. But it has no use for me now, because I can't use it in Linq query as a part of bigger select statement on entity.
I am trying to add function like this and make it the way it is mentioned here. But i am getting this exception
Additional information: LINQ to Entities does not recognize the method 'System.Nullable1[System.Int32] EwBlobIleWyst(System.String, System.Nullable1[System.Int32], System.String, System.Nullable`1[System.Int32])' method, and this method cannot be translated into a store expression.
In ssdl file function is generated like this:
<Function Name="EW_BLOB_ILE_WYST" IsComposable="true" ReturnType="decimal" BuiltIn="false" Aggregate="false" NiladicFunction="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="EWID4" StoreFunctionName="EW_BLOB_ILE_WYST">
<Parameter Name="OWNER" Type="VARCHAR2" Mode="In" />
<Parameter Name="OWNER_ID" Type="decimal" Mode="In" />
<Parameter Name="RODZ_DOK_IDS" Type="VARCHAR2" Mode="In" />
<Parameter Name="LICZ_PUSTE" Type="decimal" Mode="In" />
In csdl file it is like this :
<Function Name="EwBlobIleWyst" ReturnType="Collection(Int32)" ed:Guid="f544518f-1cdd-484c-92b4-73b61491dc54">
<Parameter Name="OWNER" Type="String" />
<Parameter Name="OWNER_ID" Type="Int32" />
<Parameter Name="RODZ_DOK_DS" Type="String" />
<Parameter Name="LICZ_PUSTE" Type="Int32" />
<DefiningExpression>SELECT EWID4.EW_BLOB_ILE_WYST(:OWNER, :OWNER_ID, :RODZ_DOK_IDS, :LICZ_PUSTE) FROM KDOK_WSK</DefiningExpression>
And my implementation looks like this :
[EdmFunction(#"Ewid4", #"EwBlobIleWyst")]
public virtual global::System.Nullable<int> EwBlobIleWyst(string OWNER, global::System.Nullable<int> OWNER_ID, string RODZ_DOK_IDS, global::System.Nullable<int> LICZ_PUSTE)
{
throw new NotSupportedException();
}
This code is inside partial context class.
And I am using it in this way :
DokPow = ((Ewid4)context).EwBlobIleWyst("smth", 1, null, 0)
This snippet is inside select of queryable using Linq
I just get a solution. The problem was in attribute, database namespace generated by Entity Developer and function and variables types.
I had to make something like that:
[DbFunction("Ewid.Database.Entities.Store", "EW_BLOB_ILE_WYST")]
public static decimal EwBlobIleWyst(string OWNER, decimal OWNER_ID, string RODZ_DOK_IDS, decimal LICZ_PUSTE)
{
throw new NotSupportedException();
}
And change types to types that was genereted in ssdl file, csdl file does not matter and there is no need in adding function in Entity Developer to model, just leave it in ssdl file and map this function by hand in c# and it works like a charm.
Related
I am trying to log the single table using NLog bypassing parameter values into each column using NLog. But somehow I couldn't able to log in to the SQL table.
I tried by passing values by passing code like this and added the targets and rules in web.config.
Code in the class
private static Logger _logger;
public CustomToken()
{
_logger = LogManager.GetLogger("apiUsageLogger");
}
_logger.Info("{clientname}", "test");
_logger.Info($"clientusername", "test");
_logger.Info($"route", "test");
_logger.Info($"parameters", "test");
_logger.Info($"isuserauthenticated", 1);
In the web.config
<target name="apiUsageLog" xsi:type="Database" connectionStringName="connStringName">
<commandtext>
INSERT INTO Table
(ClientName, ClientUserName, Route, Parameters, IsUserAuthenticated, Machine)
VALUES
(#clientname, #clientusername, #route, #parameters, #isuserauthenticated, #machine)
</commandtext>
<parameter name="#clientname" layout="${clientname}" />
<parameter name="#clientusername" layout="${clientusername}" />
<parameter name="#route" layout="${route}" />
<parameter name="#parameters" layout="${parameters}" />
<parameter name="#isuserauthenticated" layout="${isuserauthenticated}" />
<parameter name="#machine" layout="${machinename}" />
</target>
</targets>
<rules>
<<logger name="apiUsageLogger" minlevel="Info" writeTo="apiUsageLog" />
</rules>
Somehow data is not getting populated into the table.
Is there a way I can able to achieve in populating the data into appropriate columns? NLog is the right way of doing it?
Not sure if it's clear, but with database target one log message will be one record in the database. I would recommend to read the tutorial. Also in this case the database target options are good to check.
Your config isn't working as ${clientusername} doesn't exist in NLog.
I will show 3 examples, hope that make things clear
Example 1: simple logs to database target
Logger call:
logger.Info("my info message");
config:
<target name="apiUsageLog" xsi:type="Database" connectionStringName="connStringName">
<commandtext>
INSERT INTO Table
(message, machinename)
VALUES
(#message, #machinenameParam)
</commandtext>
<parameter name="#messageParam" layout="${message}" /> <!-- this will be "my info message"-->
<parameter name="#machinenameParam" layout="${machinename}" /> <!-- defined in NLog, see https://nlog-project.org/config/?tab=layout-renderers-->
</target>
</targets>
This will create a log record in the database with my info message and the machine name.
Example 2: with custom properties:
I will use structured logging here. See structured logging
Logger call:
logger.Info("my info message with {Property1}", "value1");
config:
<target name="apiUsageLog" xsi:type="Database" connectionStringName="connStringName">
<commandtext>
INSERT INTO Table
(message, machinename, property1)
VALUES
(#message, #machinenameParam, #propertyParam1)
</commandtext>
<parameter name="#messageParam" layout="${message}" /> <!-- this will be "my info message"-->
<parameter name="#machinenameParam" layout="${machinename}" /> <!-- defined in NLog, see https://nlog-project.org/config/?tab=layout-renderers-->
<parameter name="#propertyParam1" layout="${event-properties:Property1}" /> <!-- this will be "value1" -->
</target>
</targets>
This will create a log record in the database with my info message with "Value1" , the machine name and the custom property with "value1".
Example 3: custom properties, not all in the message
This combines structured logging and WithProperty. You need at least NLog 4.6.3 for this.
Logger call:
logger.WithProperty("Property2", "value2")
.Info("my info message {Property1}", "value1");
config:
<target name="apiUsageLog" xsi:type="Database" connectionStringName="connStringName">
<commandtext>
INSERT INTO Table
(message, machinename, property1, property2)
VALUES
(#message, #machinenameParam, #propertyParam2)
</commandtext>
<parameter name="#messageParam" layout="${message}" /> <!-- this will be: my info message with "value1"-->
<parameter name="#machinenameParam" layout="${machinename}" /> <!-- defined in NLog, see https://nlog-project.org/config/?tab=layout-renderers-->
<parameter name="#propertyParam1" layout="${event-properties:Property1}" /> <!-- this will be "value1" -->
<parameter name="#propertyParam2" layout="${event-properties:Property2}" /> <!-- this will be "value2" -->
</target>
</targets>
This will create a log record in the database with my info message with "Value1" , the machine name and the custom properties "value1" and "value2"
Note, now "value1" is in the message and "value2" isn't.
Having trouble with nHibernate mapping my enum to the DB.
Tried looking at the mapping but can't see anything wrong, my suspicions by this point are that it may have something to do with the enum?
Here's Fortron.Crm.Domain.Policy:
namespace Fortron.Crm.Domain
{
[Serializable]
public class Policy
{
private PolicyStatus _policyStatus;
public PolicyStatus PolicyStatus
{
get { return _policyStatus; }
set { _policyStatus = value; }
}
}
Here's the class mapping
<class name="Fortron.Crm.Domain.Policy, Fortron.Crm.Domain" table="Policy" lazy="false">
<id name="Id" access="nosetter.camelcase-underscore" column="PolicyId" unsaved-value="-1">
<generator class="identity" />
</id>
<set name="Claims" access="field.camelcase-underscore" inverse="true" lazy="false" cascade="save-update">
<key column="PolicyId" />
<one-to-many class="Fortron.Crm.Domain.Claim, Fortron.Crm.Domain" />
</set>
<many-to-one name="Product" column="ProductId" access="nosetter.camelcase-underscore" />
<property name="PolicyNumber" />
<property name="VehicleRegistrationNumber" />
<property name="ContractNumber" />
<property name="ContractPaymentAuthorised" />
<property name="ContractPaymentAuthorisedAt" />
<component name="Contact" access="nosetter.camelcase-underscore">
<property name="Title" />
<property name="GivenNames" />
<property name="Surname" />
<property name="BusinessName" />
<property name="DateOfBirth" />
<property name="Gender" column="GenderId" />
<property name="TelephoneNumber" />
<property name="MobileTelephoneNumber" />
<property name="WorkTelephoneNumber" />
<component name="Address" access="nosetter.camelcase-underscore">
<property name="StreetLine1" column="StreetLine1" />
<property name="StreetLine2" column="StreetLine2" />
<property name="CityTown" column="CityTown" />
<property name="Postcode" column="Postcode" />
<many-to-one name="StateTerritory" column="StateTerritoryId" />
</component>
</component>
<property name="CustomerNumber" column="CustomerNumber" not-null="false" />
<property name="Vin" column="Vin" not-null="false" />
<property name="PolicyStatus" column="PolicyStatusId" />
</class>
Lastly here's the stack trace:
Service cannot be started. System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> NHibernate.MappingException: Could not compile the mapping document: Fortron.Crm.Domain.Policy.hbm.xml ---> NHibernate.MappingException: Problem trying to set property type by reflection ---> NHibernate.MappingException: class Fortron.Crm.Domain.Policy, Fortron.Crm.Domain, Version=2.0.0.1, Culture=neutral, PublicKeyToken=6f168f2566a816b4 not found while looking for property: PolicyStatus ---> NHibernate.PropertyNotFoundException: Could not find a getter for property 'PolicyStatus' in class 'Fortron.Crm.Domain.Policy'
at NHibernate.Properties.BasicPropertyAccessor.GetGetter(Type type, String propertyName)
at NHibernate.Util.ReflectHelper.ReflectedPropertyClass(String className, String name, String accessorName)
--- End of inner exception stack trace ---
at NHibernate.Util.ReflectHelper.ReflectedPropertyClass(String className, String name, String accessorName)
at NHibernate.Mapping....
Any ideas?
Change your member signature to make it virtual:
public virtual PolicyStatus PolicyStatus
NHibernate expects all the members of your entity to be virtual for binding. This is necessary because NHibernate creates proxy (to implement lazy loading) in certain cases. Without marked as virtual, this will not be possible for NHibernate.
You may refer this (or archive) article:
The quick answer to that question is: because we need members to be virtual in order to do our lazy loading magic/voodoo.
The longer answer is more interesting though. An important feature that any real ORM must have is transparent Lazy Loading. If you retrieve an object through an ORM, you don't want it to automatically pull in an entire object graph (not by default anyway), yet you don't want to litter your code with checks to see if certain associations have been loaded yet, and then loading them if necessary. This is the ORM's responsibility. Ideally, you want to be able to access properties and have the ORM load the necessary data upon first access of those properties if the data hasn't been retrieved yet.
NHibernate has this ability, yet it doesn't require you to inherit from some kind of NHibernate base class or implement any interfaces or anything like that. So how does it work? Well, NHibernate uses proxies of your classes at runtime whenever lazy loading is required. Ok, so what exactly is a proxy? In this case, an NHibernate proxy is a type which is generated dynamically when NHibernate is initialized for your application (this only happens once upon application startup). A proxy type will be generated for each of your entities that hasn't explicitly been mapped to avoid lazy loading (more on this later). A proxy type for one of your entities will actually inherit from your entity, and will then intercept each possible call you can perform on that type.
So i'm trying to build a c# binding from a Android AAR, and i was following this guide https://developer.xamarin.com/guides/android/advanced_topics/binding-a-java-library/binding-an-aar/
But i'm running into an error like this
Severity Code Description Project File Line Suppression State
Error CS0534 'VaultManagerPaymentMethodsAdapter' does not implement inherited abstract member 'RecyclerView.Adapter.OnBindViewHolder(RecyclerView.ViewHolder, int)' Braintree.DropIn Path\Braintree.DropIn\obj\Release\generated\src\Com.Braintreepayments.Api.Dropin.Adapters.VaultManagerPaymentMethodsAdapter.cs 9 Active
And
Severity Code Description Project File Line Suppression State
Error CS0534 'VaultManagerPaymentMethodsAdapter' does not implement inherited abstract member 'RecyclerView.Adapter.OnCreateViewHolder(ViewGroup, int)' Braintree.DropIn Path\Braintree.DropIn\obj\Release\generated\src\Com.Braintreepayments.Api.Dropin.Adapters.VaultManagerPaymentMethodsAdapter.cs 9 Active
But if i try to add things to MetaData, i get errors saying that its already defined
<add-node path="/api/package[#name='com.braintreepayments.api.dropin.adapters']/class[#name='VaultManagerPaymentMethodsAdapter']">
<method abstract="false"
deprecated="not deprecated"
final="false"
name="onBindViewHolder"
native="false"
return="void"
static="false"
synchronized="false"
visibility="public">
<parameter name="holder"
type="android.support.v7.widget.RecyclerView.ViewHolder">
</parameter>
<parameter name="position"
type="int">
</parameter>
</method>
</add-node>
<add-node path="/api/package[#name='com.braintreepayments.api.dropin.adapters']/class[#name='VaultManagerPaymentMethodsAdapter']">
<method abstract="false"
deprecated="not deprecated"
final="false"
name="onCreateViewHolder"
native="false"
return="android.support.v7.widget.RecyclerView.ViewHolder"
static="false"
synchronized="false"
visibility="public">
<parameter name="parent"
type="android.view.ViewGroup">
</parameter>
<parameter name="viewType"
type="int">
</parameter>
</method>
</add-node>
any inputs would be appreciated
The temporary solution to this was to remove the node , not the ideal solution but since i don't need that specific thing, i just removed it
I have an ODATA server built with WebApi where my container has only an entity set of 'calendars'. In turn, each 'calendar' has a navigation property which is a collection of 'appointments' and a function to 'getCalendarView', which returns a subset of such appointments. The appointments are contained in the calendar, meaning there is no entity set in the container with them.
When I call 'getCalendarView' asking for minimal metadata, I get back the results. However, if I ask for the full metadata, I get this error:
"Parent id or contained context url is missing which is required to compute id for contained instance."
If I understand this correctly, the framework does not know who is the parent calendar of the returned appointments, so it fails to produce the links that represent each entity. How can I provide this info?
The error message continues with "Specify ODataUri in the ODataMessageWriterSettings or return parent id or context url in the payload.", but I don't know how that translates to code in WebApi.
I don't have access to the ODataMessageWriterSettings in my WebApi controller (I suppose) so the first suggestion does not seem to apply. So how do I "return parent id or context url in the payload"?
Is there a way to tag the controller method or the returned entities in any way to provide the info?
If it helps, the metadata looks somewhat like this:
<EntityType Name="appointment">
...
</EntityType>
<EntityType Name="calendar">
...
<NavigationProperty Name="appointments" Type="Collection(appointment)" ContainsTarget="true" />
...
</EntityType>
<Function Name="getCalendarView" IsBound="true" EntitySetPath="calendar/appointments">
<Parameter Name="calendar" Type="calendar" Nullable="false" />
<Parameter Name="start" Type="Edm.DateTimeOffset" Nullable="false" />
<Parameter Name="end" Type="Edm.DateTimeOffset" Nullable="false" />
<ReturnType Type="Collection(appointment)" Nullable="false" />
</Function>
<EntityContainer Name="container">
<EntitySet Name="calendars" EntityType="calendars" />
...
</EntityContainer>
I'm not 100% if I'm using EntitySetPath correctly.
My controller code goes like this:
[ODataRoutePrefix("calendars({calendarId})")]
public class CalendarController
{
...
[HttpGet]
[ODataRoute("getCalendarView(start={start},end={end})")]
public Task<IQueryable<Appointment>> GetCalendarView(DateTimeOffset start, DateTimeOffset end) =>
...
}
In code, Appointment and Calendar are simple POCO classes, with their respective properties. Does they need any special property to indicate its parent id or context url?
Thanks
I have an object of type Video. I am storing Videos in my database, but I want each video entry to be unique. Uniqueness is determined by an 11-digit string provided by the client.
As such, I've generated this Video.hbm.xml file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Streamus" namespace="Streamus.Domain">
<class name="Video" table="[Videos]" lazy="false" mutable="false">
<id name="Id" length="11" type="String" />
<property name="Title" not-null="true" />
<property name="Duration" not-null="true" />
<property name="Author" not-null="true" />
</class>
</hibernate-mapping>
I have no intention of deleting or updating any entries to this table. So, I've tagged my class as immutable.
Now, I thought this was a pretty good way of going about things, but I am experiencing issues with cascade-updating from a parent object. Because my ID is generated client-side, and I do not leverage a second identifier, NHibernate is unable to reliably determine whether a Video needs to be Inserted or Updated (note that it should never update due to being immutable.)
Something like:
Video video = new Video("s91jgcmQoB0", "Tristam - Chairs", 219, "MeoMix");
new VideoManager().Save(video);
// Create a new PlaylistItem and write it to the database.
string title = video.Title;
PlaylistItem playlistItem = new PlaylistItem(title, video);
Playlist.AddItem(playlistItem);
PlaylistManager.SavePlaylistItem(playlistItem);
where PlaylistItem's hbm.xml references Video as:
<many-to-one name="Video" column="VideoId" not-null="true" cascade="save-update" />
The above code generates a NonUniqueObjectException. This is because the VideoManager works with the Video in one session, closes it, then PlaylistManager re-references the same Video in a new Session, but NHibernate can't accomodate because it doesn't have good IDs to go off of.
Removing the option of cascade="save-update" fixes the issue, but then I don't get the benefit of having my Video object created implicitly in the database by NHibernate. Instead, I would have to manually save the Video object and, afterwards, save the PlaylistItem object. This is clearly not ideal.
So, I'm wondering -- should I be assigning a GUID to my Video object? If so, how can I enforce the fact that I only wish to have unique Video entries in my table where uniqueness is defined by the 11 digit string ID?
Let me know if I can provide any more information to make this more clear.
First of all modify your ID section in you video.hbm.xml to have an "assigned" generator
<id name="id" ....>
<generator class="assigned" />
</id>
That tells nhibernate that ur IDs are manually generated from the client.
Also having ur same object being manipulated by multiple session will cause consistency errors. So either use a unique session for your batch of actions or make sure ur object is properly tracked in all sessions by using session.Merge