I have been trying to create a calculated property in my persistence layer by follow
Hendry Luk's solution for calculated properties.
I am able to select the values from the DB using a linq query:
var result = from parcel in Repository.Query();
When I try to do a where on the selected result, I get a could not resolve property error.
Here is what my code looks like.
My Model:
namespace ConsoleApplication14
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
public class Common1 : ICommon
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
//public static readonly Expression<Func<Common1, string>> CalculatedDisplayExpression = x => ("Common 1 Display: " + x.Id + " - " + x.Name);
public static readonly Expression<Func<Common1, string>> CalculatedDisplayExpression = x => (x.Id + "");
private static readonly Func<Common1, string> CalculateDisplay = CalculatedDisplayExpression.Compile();
public virtual string Display { get { return CalculateDisplay(this); } }
}
}
My Interface the model implementing:
namespace ConsoleApplication14
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;`enter code here`
public interface ICommon
{
int Id { get; set; }
string Name { get; set; }
string Display { get; }
}
}
Model's mapping
namespace ConsoleApplication14
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate.Mapping.ByCode;
using NHibernate.Mapping.ByCode.Conformist;
public class Common1Map : ClassMapping<Common1>
{
public Common1Map()
{
Id(x => x.Id, map => map.Generator(Generators.Native));
Property(x => x.Name);
}
}
}
namespace ConsoleApplication14
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using NHibernate.Hql.Ast;
using NHibernate.Linq;
using NHibernate.Linq.Functions;
using NHibernate.Linq.Visitors;
public class CalculatedPropertyGenerator<T, TResult> : BaseHqlGeneratorForProperty
{
public static void Register(ILinqToHqlGeneratorsRegistry registry, Expression<Func<T, TResult>> property, Expression<Func<T, TResult>> calculationExp)
{
registry.RegisterGenerator(ReflectionHelper.GetProperty(property), new CalculatedPropertyGenerator<T, TResult> { _calculationExp = calculationExp });
}
private CalculatedPropertyGenerator() { }
private Expression<Func<T, TResult>> _calculationExp;
public override HqlTreeNode BuildHql(MemberInfo member, Expression expression, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
return visitor.Visit(_calculationExp);
}
}
}
namespace ConsoleApplication14
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Cfg.MappingSchema;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Tool.hbm2ddl;
using NHibernate.Mapping.ByCode;
using NHibernate.Mapping;
using Iesi.Collections.Generic;
using System.Reflection;
using NHibernate.Linq.Functions;
using NHibernate.Linq;
public class SessionProvider
{
private static ISessionFactory sessionFactory;
public static SessionProvider Instance { get; private set; }
//DefaultLinqToHqlGeneratorsRegistry registry = new DefaultLinqToHqlGeneratorsRegistry();
ILinqToHqlGeneratorsRegistry registry = new DefaultLinqToHqlGeneratorsRegistry();
static SessionProvider()
{
var provider = new SessionProvider();
provider.Initialize();
Instance = provider;
}
private SessionProvider() { }
private void Initialize()
{
const string connString = "server=(local)\\mssql2008;database=Common;integrated security=sspi";
Configuration configuration = new Configuration();
configuration
.DataBaseIntegration(db =>
{
db.ConnectionString = connString;
db.Dialect<MsSql2008Dialect>();
db.Driver<SqlClientDriver>();
db.LogSqlInConsole = true;
db.IsolationLevel = System.Data.IsolationLevel.ReadCommitted;
})
.AddDeserializedMapping(GetMappings(), null);
CalculatedPropertyGenerator<Common1, string>.Register(registry, x => x.Display, Common1.CalculatedDisplayExpression);
// registry.RegisterGenerator(ReflectionHelper.GetProperty<Common1, string>(x => x.Display), new CalculatedPropertyGenerator());
var exporter = new SchemaExport(configuration);
exporter.Execute(true, true, false);
sessionFactory = configuration.BuildSessionFactory();
}
private HbmMapping GetMappings()
{
ModelMapper mapper = new ModelMapper();
mapper.AddMappings(Assembly.GetAssembly(typeof(Common1Map)).GetExportedTypes());
HbmMapping mappings = mapper.CompileMappingForAllExplicitlyAddedEntities();
return mappings;
}
public ISession OpenSession()
{
return sessionFactory.OpenSession();
}
}
}
Client:
namespace ConsoleApplication14
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Linq;
using NHibernate.Linq.Functions;
public class Tester
{
private ILinqToHqlGeneratorsRegistry registry = new DefaultLinqToHqlGeneratorsRegistry();
public void Go()
{
using (ISession session = SessionProvider.Instance.OpenSession())
{
CreateData(session);
IQueryable<ICommon> commons = session.Query<ICommon>();//.Where(x => x.Display.Contains("Common1 #7"));
var common1 = session.Query<Common1>().Where(x => x.Display.Contains("Common1 #7"));
foreach(var common in commons)
{
Console.WriteLine(common.Display);
}
}
}
private void CreateData(ISession session)
{
using (ITransaction tx = session.BeginTransaction())
{
for (int i = 0; i < 10; i++)
{
session.SaveOrUpdate(new Common1() { Name = "Common1 #" + i });
}
tx.Commit();
}
}
}
}
Register in SessionProvider class, like
configuration.LinqToHqlGeneratorsRegistry<MyLinqToHqlGeneratorsRegistry>();
MyLinqToHQLGeneratorRegistry implementation looks like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate.Linq.Functions;
using NHibernate.Linq;
namespace ConsoleApplication14
{
public class MyLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
public MyLinqToHqlGeneratorsRegistry()
: base()
{
CalculatedPropertyGenerator<Common1, string>.Register(this, x => x.Display, Common1.CalculatedDisplayExpression);
}
}
}
You need to derive a class from DefaultLinqToHqlGeneratorsRegistry. Add the registration logic in its constructor (passing 'this' to CalculatedPropertyGenerator<>.Register()). Then register the class with the NHibernate configuration using:
cfg.LinqToHqlGeneratorsRegistry<OurLinqFunctionRegistry>();
Related
Here is my method file looks like
`
public List<NewAssetChangeApproval> GetNewAssetChangeApprovals(int userId, bool isHistory)
{
List<NewAssetChangeApproval> nac;
SqlParameter[] parms =
{
new SqlParameter ("changeType", "Asset"),
new SqlParameter ("userId", userId)
};
if (isHistory)
nac = DbContext.Database.SqlQuery<NewAssetChangeApproval>("EXEC AM.GetAssetChangeApprovalsHistory #changeType, #userId", parms).ToList();
else
nac = DbContext.Database.SqlQuery<NewAssetChangeApproval>("EXEC AM.GetAssetChangeApprovals #changeType, #userId", parms).ToList();
return nac;
}
`
I Am unable to call the SQL connection from this method.
I tried using FakeDB and Test base files. below is my Test Base.
`
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Teneo.Core.Models.Database.Parser;
namespace Teneo.ParserFileDirector.Test.Common
{
public class TestBase
{
private bool useSqlite;
public ParserDataContext GetDbContext()
{
var builder = new DbContextOptionsBuilder<ParserDataContext>();
if (useSqlite)
{
// Use SqliteDb..
builder.UseSqlite("Datasource=:memory:", x => { });
}
else
{
// Use In-memory Db...
builder.UseInMemoryDatabase(Guid.NewGuid().ToString());
}
var dbcontext = new ParserDataContext(builder.Options);
if (useSqlite)
{
dbcontext.Database.OpenConnection();
}
else { dbcontext.Database.EnsureCreated(); }
// dbcontext.Database.EnsureCreated();
return dbcontext;
}
public void UseSqlite()
{
useSqlite = true;
}
}
}
`
I tried using the above TestBase i have created but I am unable to call it properly. is there is nay way to call the SQL connections?
I have this following interface IQueueClient implements AZureBus class;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Messaging;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.Management.ServiceBus;
namespace MessageQueueApp
{
public class AZBus:IQueueService
{
public string ConnectionString { get; set; }
public string QueueName { get; set; }
private static IQueueClient queueClient;
public void Send(string payload)
{
queueClient = new QueueClient(ConnectionString, QueueName);
var message = new Message(Encoding.UTF8.GetBytes(payload));
queueClient.SendAsync(message).Wait();
}
}
}
I am getting an error on my new object name QueueClient() with argument types ConnectionString, QueueName. As well my SendAsync(message).Wait(); What am i missing from this code? Please help and show me guidance to this, thanks.
You are missing a using statement:
using Microsoft.Azure.ServiceBus;
I wish to alias the name of my request object properties, so that these requests both work and both go to the same controller:
myapi/cars?colors=red&colors=blue&colors=green and myapi/cars?c=red&c=blue&c=green
for request object:
public class CarRequest {
Colors string[] { get; set; }
}
Has anyone been able to use the new ModelBinders to solve this without having to write ModelBindings from scratch?
Here is a similar problem for an older version of asp.net and also here
I wrote a model binder to do this:
EDIT:
Here's the repo on github. There are two nuget packages you can add to your code that solve this problem. Details in the readme
It basically takes the place of the ComplexTypeModelBinder (I'm too cowardly to replace it, but I slot it in front with identical criteria), except that it tries to use my new attribute to expand the fields it's looking for.
Binder:
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MYDOMAIN.Client;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.Extensions.Logging;
namespace MYDOMAIN.Web.AliasModelBinder
{
public class AliasModelBinder : ComplexTypeModelBinder
{
public AliasModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders, ILoggerFactory loggerFactory,
bool allowValidatingTopLevelNodes)
: base(propertyBinders, loggerFactory, allowValidatingTopLevelNodes)
{
}
protected override Task BindProperty(ModelBindingContext bindingContext)
{
var containerType = bindingContext.ModelMetadata.ContainerType;
if (containerType != null)
{
var propertyType = containerType.GetProperty(bindingContext.ModelMetadata.PropertyName);
var attributes = propertyType.GetCustomAttributes(true);
var aliasAttributes = attributes.OfType<BindingAliasAttribute>().ToArray();
if (aliasAttributes.Any())
{
bindingContext.ValueProvider = new AliasValueProvider(bindingContext.ValueProvider,
bindingContext.ModelName, aliasAttributes.Select(attr => attr.Alias));
}
}
return base.BindProperty(bindingContext);
}
}
}
Provider:
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.Extensions.Logging;
namespace MYDOMAIN.Web.AliasModelBinder
{
public class AliasModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType)
{
var propertyBinders = new Dictionary<ModelMetadata, IModelBinder>();
foreach (var property in context.Metadata.Properties)
{
propertyBinders.Add(property, context.CreateBinder(property));
}
return new AliasModelBinder(propertyBinders,
(ILoggerFactory) context.Services.GetService(typeof(ILoggerFactory)), true);
}
return null;
}
/// <summary>
/// Setup the AliasModelBinderProvider Mvc project to use BindingAlias attribute, to allow for aliasing property names in query strings
/// </summary>
public static void Configure(MvcOptions options)
{
// Place in front of ComplexTypeModelBinderProvider to replace this binder type in practice
for (int i = 0; i < options.ModelBinderProviders.Count; i++)
{
if (options.ModelBinderProviders[i] is ComplexTypeModelBinderProvider)
{
options.ModelBinderProviders.Insert(i, new AliasModelBinderProvider());
return;
}
}
options.ModelBinderProviders.Add(new AliasModelBinderProvider());
}
}
}
Value Provider:
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Primitives;
namespace MYDOMAIN.Web.AliasModelBinder
{
public class AliasValueProvider : IValueProvider
{
private readonly IValueProvider _provider;
private readonly string _originalName;
private readonly string[] _allNamesToBind;
public AliasValueProvider(IValueProvider provider, string originalName, IEnumerable<string> aliases)
{
_provider = provider;
_originalName = originalName;
_allNamesToBind = new[] {_originalName}.Concat(aliases).ToArray();
}
public bool ContainsPrefix(string prefix)
{
if (prefix == _originalName)
{
return _allNamesToBind.Any(_provider.ContainsPrefix);
}
return _provider.ContainsPrefix(prefix);
}
public ValueProviderResult GetValue(string key)
{
if (key == _originalName)
{
var results = _allNamesToBind.Select(alias => _provider.GetValue(alias)).ToArray();
StringValues values = results.Aggregate(values, (current, r) => StringValues.Concat(current, r.Values));
return new ValueProviderResult(values, results.First().Culture);
}
return _provider.GetValue(key);
}
}
}
And an attribute to go in / be referenced by the client project
using System;
namespace MYDOMAIN.Client
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class BindingAliasAttribute : Attribute
{
public string Alias { get; }
public BindingAliasAttribute(string alias)
{
Alias = alias;
}
}
}
Configured in the Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services
...
.AddMvcOptions(options =>
{
AliasModelBinderProvider.Configure(options);
...
})
...
Usage:
public class SomeRequest
{
[BindingAlias("f")]
public long[] SomeVeryLongNameForSomeKindOfFoo{ get; set; }
}
leading to a request that looks either like this:
api/controller/action?SomeVeryLongNameForSomeKindOfFoo=1&SomeVeryLongNameForSomeKindOfFoo=2
or
api/controller/action?f=1&f=2
I put most things in my web project, and the attribute in my client project.
This is my first WCF Server:
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
namespace Myns.MBClient
{
[ServiceContract]
public interface IManagementConsole
{
[OperationContract]
ConsoleData GetData(int strategyId);
}
[ServiceContract]
public class ConsoleData
{
private int currentIndicator;
[OperationContract]
public double GetCurrentIndicator()
{
return currentIndicator;
}
public void SetCurrentIndicator(int currentIndicator)
{
this.currentIndicator = currentIndicator;
}
}
class ManagementConsole : IManagementConsole
{
public ConsoleData GetData(int strategyId)
{
ConsoleData data = new ConsoleData();
data.SetCurrentIndicator(33);
return data;
}
}
}
In client I just call pipeProxy.GetData(0).GetCurrentIndicator()
Why program prints 0 while it supposed to print 33?
Client code (which I think has no problems):
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using Commons;
using myns.MBClient;
namespace myns.MBClientConsole
{
class Program
{
static void Main(string[] args)
{
ChannelFactory<IManagementConsole> pipeFactory =
new ChannelFactory<IManagementConsole>(
new NetNamedPipeBinding(),
new EndpointAddress(
"net.pipe://localhost/PipeMBClientManagementConsole"));
IManagementConsole pipeProxy =
pipeFactory.CreateChannel();
while (true)
{
string str = Console.ReadLine();
Console.WriteLine("pipe: " +
pipeProxy.GetData(0).GetCurrentIndicator());
}
}
}
}
If you create your own complex type to use with WCF you have to add a DataContract attribute instead of a ServiceContract, and you should use fields/properties that are decorated with DataMember. And do yourself a favor and use plain DTOs (DataTransferObjects - Objects with only fields/properties but no behavior):
[DataContract]
public class ConsoleData
{
[DataMember]
public int CurrentIndicator {get;set;}
}
You can find more on this here
I have folowing class
public class Foo
{
public Foo(int max=2000){...}
}
and I want to use Ninject to inject a constant value into Foo. I have try this
Bind<Foo>().ToSelft().WithConstructorArgument("max", 1000);
but I get following error when I try to use _ninject.Get<Foo>:
Error activating int
No matching bindings are available, and the type is not self-bindable.
Activation path:
3) Injection of dependency int into parameter max of constructor of type Foo
the below works for me:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ninject;
using Ninject.Activation;
using Ninject.Syntax;
public class Foo
{
public int TestProperty { get; set; }
public Foo(int max = 2000)
{
TestProperty = max;
}
}
public class Program
{
public static void Main(string [] arg)
{
using (IKernel kernel = new StandardKernel())
{
kernel.Bind<Foo>().ToSelf().WithConstructorArgument("max", 1000);
var foo = kernel.Get<Foo>();
Console.WriteLine(foo.TestProperty); // 1000
}
}
}