Fluent NHibernate Error with embedded statements - nhibernate

this is my code;
public ActionResult Login(User user, string returnUrl)
{
using (ISession session = FluentNHibernateConnect.OpenSession())
var users = session.QueryOver<User>()
.Where(user.Nick == "asd")
.And(user.Password == "1234")
.List();
}
what is the problem. var and .where(user.nick == "asd") red line ?
Library;
MvcBlog.Mapping;
MvcBlog.Models;
NHibernate;
NHibernate.Criterion;
System.Web.Mvc;
System.Web;
System.Web.Security;

Where method takes an expression:
var users = session.QueryOver<User>()
.Where(user => user.Nick == "asd")
.And(user => user.Password == "1234")
.List();

Related

Copy routes to new HttpContext

I use the following code to create a new DefaultHttpContext and use it to render views to strings.
var httpContext = new DefaultHttpContext();
if (serviceProvider.GetService<IHttpContextAccessor>() is { } accessor)
{
accessor.HttpContext = httpContext;
}
var website = page.WebsitePageModel as WebsitePageModel;
var domain = website?.PrimaryDomain;
if (website != null && domain != null)
{
httpContext.Request.Host = "host"
httpContext.Request.Scheme = "https";
httpContext.Request.Path = "/my-page"
}
httpContext.RequestServices = serviceProvider;
var routeData = httpContext.GetRouteData();
routeData.Routers.Add(new RouteCollection());
This works well until I try to render a view component that uses routes/endpoints, e.g.
string url = Url.Action("MyAction", "MyController");
The url will be null because the controller does not know any routes. How can I access the routes of my web application and copy them to the controller?
If you just want to get the route, I found another way, but I don't know if it helps you.
I get all registered routes using IActionDescriptorCollectionProvider:
#using Microsoft.AspNetCore.Mvc.Infrastructure
#inject IActionDescriptorCollectionProvider provider
#{
var urls = provider.ActionDescriptors.Items
.Select(descriptor => "/" + string.Join('/', descriptor.RouteValues.Values
.Where(v => v != null)
.Select(c => c.ToLower())
.Reverse()))
.Distinct()
.ToList();
}
#foreach (var item in #urls)
{
#item
}

Duplicate records created in IActionResult (Entity Framework Core)

I have no idea why the following code sometimes create duplicate records with different record ID. I suspect the user has post multiple times. If so, how should I change the code to prevent this?
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Add(LeaveHandleViewModel LeaveVM)
{
//Check if record exists
if (_context.InOutRecords.Where(x => x.User == User.Identity.Name
&& x.StartForm == LeaveVM.TodayDate).Count() > 0)
{
//Modify record
var LeaveRecord = _context.InOutRecords.Where(x => x.Email == User.Identity.Name
&& x.StartForm == LeaveVM.TodayDate).FirstOrDefault();
LeaveRecord.Remarks = LeaveVM.TodayRemarks;
var entry = _context.Entry(LeaveRecord);
entry.State = EntityState.Modified;
_context.SaveChanges();
return RedirectToAction("Index");
}
else
{
//create new record
Leave LeaveRecord = new Leave();
LeaveRecord.Remarks = LeaveVM.TodayRemarks;
LeaveRecord.StartForm = LeaveVM.TodayDate;
LeaveRecord.User = User.Identity.Name;
LeaveRecord.CreateDate = DateTime.Now;
_context.InOutRecords.Add(LeaveRecord);
_context.SaveChanges();
return RedirectToAction("Index");
}
}
Check if the problem is not because of date comparison x.StartForm == LeaveVM.TodayDate or because of some special characters that are in username.
Oh and try code below and let me know if something changed.
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Add(LeaveHandleViewModel LeaveVM)
{
var inOutRecord = _context.InOutRecords.FirstOrDefault(x => x.User == User.Identity.Name
&& x.StartForm == LeaveVM.TodayDate);
if(inOutRecord != null)
{
//Edit already existing record
inOutRecord.Remarks = LeaveVM.TodayRemarks;
_context.InOutRecords.Update(inoutRecord);
_context.SaveChanges();
return RedirectToAction(nameOf(Index));
}else
{
//Create new one
Leave LeaveRecord = new Leave();
LeaveRecord.Remarks = LeaveVM.TodayRemarks;
LeaveRecord.StartForm = LeaveVM.TodayDate;
LeaveRecord.User = User.Identity.Name;
LeaveRecord.CreateDate = DateTime.Now;
_context.InOutRecords.Add(LeaveRecord);
_context.SaveChanges();
return RedirectToAction(nameOf(Index));
}
}

Flag / Unflag email sending in CRM 2011

In CRM 2011, I want to attach Contacts to Quote, no problems for that.
When I save the quote, for each Contact I want to send a email for reminder purpose. (With a plugin)
How It's possible to flag this and give the ability to CRM user to unflag this from the quote form with a checkbox.
The final purpose, It's to give the ability to CRM user to send a new email reminder to one or multiple contacts attached in the quote.
Can you help me ?
You will need to have a ribbon button that will call a JavaScript method in one of the web-resources.
In the CommandDefinition of you RibbonDiff XML you will need to send a parameter to the JS method which will contain all the IDs of selected records in the subgrid.
<CommandDefinitions>
<CommandDefinition Id="xyz.Button.SendEmail.command">
<EnableRules>
</EnableRules>
<DisplayRules>
</DisplayRules>
<Actions>
<JavaScriptFunction Library="$webresource:Test.Js" FunctionName="SendEmail">
<CrmParameter Value="SelectedControlAllItemIds" />
</JavaScriptFunction>
</Actions>
</CommandDefinition>
and then the JS method would be something like below wherein you will need to parse all the IDs and then process your logic
function SendEmail(selectedIds) {
if (selectedIds != null && selectedIds != “”) {
var strIds = selectedIds.toString();
var arrIds = strIds.split(“, ”);
for (var indxIds = 0; indxIds < arrIds.length; indxIds++) {
//The logic that you want to process on each record will come here.
}
} else {
alert(“No records selected !! !”);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Crm;
using Microsoft.Xrm.Sdk;
using System.ServiceModel;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.Sdk.Messages;
using System.Text.RegularExpressions;
using System.Xml.Linq;
namespace SendEmail
{
public class Email : IPlugin
{
public void Execute(IServiceProvider serviceprovider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceprovider.GetService(typeof(IPluginExecutionContext));
if (!(context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity))
return;
//entity
Entity ent = (Entity)context.InputParameters["Target"];
if (ent.LogicalName != "entityName")//EntityName
throw new InvalidPluginExecutionException("Not a Service Request record! ");
//service
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceprovider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService _service = serviceFactory.CreateOrganizationService(context.UserId);
string Email="";
if (ent.Contains("emailidfiled"))
Email = (string)ent["emailidfiled"];
#region email template
QueryExpression query = new QueryExpression()
{
EntityName = "template",
Criteria = new FilterExpression(LogicalOperator.And),
ColumnSet = new ColumnSet(true)
};
query.Criteria.AddCondition("title", ConditionOperator.Equal, "templateName");
EntityCollection _coll = _service.RetrieveMultiple(query);
if (_coll.Entities.Count == 0)
throw new InvalidPluginExecutionException("Unable to find the template!");
if (_coll.Entities.Count > 1)
throw new InvalidPluginExecutionException("More than one template found!");
var subjectTemplate = "";
if (_coll[0].Contains("subject"))
{
subjectTemplate = GetDataFromXml(_coll[0]["subject"].ToString(), "match");
}
var bodyTemplate = "";
if (_coll[0].Contains("body"))
{
bodyTemplate = GetDataFromXml(_coll[0]["body"].ToString(), "match");
}
#endregion
#region email prep
Entity email = new Entity("email");
Entity entTo = new Entity("activityparty");
entTo["addressused"] =Email;
Entity entFrom = new Entity("activityparty");
entFrom["partyid"] = "admin#admin.com";
email["to"] = new Entity[] { entTo };
email["from"] = new Entity[] { entFrom };
email["regardingobjectid"] = new EntityReference(ent.LogicalName, ent.Id);
email["subject"] = subjectTemplate;
email["description"] = bodyTemplate;
#endregion
#region email creation & sending
try
{
var emailid = _service.Create(email);
SendEmailRequest req = new SendEmailRequest();
req.EmailId = emailid;
req.IssueSend = true;
GetTrackingTokenEmailRequest wod_GetTrackingTokenEmailRequest = new GetTrackingTokenEmailRequest();
GetTrackingTokenEmailResponse wod_GetTrackingTokenEmailResponse = (GetTrackingTokenEmailResponse)
_service.Execute(wod_GetTrackingTokenEmailRequest);
req.TrackingToken = wod_GetTrackingTokenEmailResponse.TrackingToken;
_service.Execute(req);
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException("Email can't be saved / sent." + Environment.NewLine + "Details: " + ex.Message);
}
#endregion
}
private static string GetDataFromXml(string value, string attributeName)
{
if (string.IsNullOrEmpty(value))
{
return string.Empty;
}
XDocument document = XDocument.Parse(value);
// get the Element with the attribute name specified
XElement element = document.Descendants().Where(ele => ele.Attributes().Any(attr => attr.Name == attributeName)).FirstOrDefault();
return element == null ? string.Empty : element.Value;
}
}
}

RavenDB StartsWith Variable on left-hand-side of Query

I have a collection of docs with a Url property that looks like:
{ Url: www.test.com }
{ Url: www.test.com/abc }
{ Url: www.test.com/abc/xyz }
I want to query the docs with www.test.com/abc such that I am returned all the documents that match the url on everything up-to-and-including the query url. i.e. the results would return:
{ Url: www.test.com }
{ Url: www.test.com/abc }
Below is the query I have written to accomplish this. As you can see, it relies on the 'Starts With' to be performed on the queryTerm, as opposed to being performed on a property of the document (the left-hand-side of the query).
var queryTerm = "www.test.com/abc";
pages = session.Query<MyDocument>()
.Where(x => queryTerm.StartsWith(x.Url));
This does not work in Raven; I get an 'Expression type not supported' error. Any ideas?
Raven doesn't appear to support that in its expression. Interestingly, the query x => queryTerm.StartsWith(x.Url) can be exploded into something along the lines of:
x => x.Url == queryTerm ||
x.Url == queryTerm.Remove(queryTerm.Length - 1) ||
x.Url == queryTerm.Remove(queryTerm.Length - 2) ||
x.Url == queryTerm.Remove(queryTerm.Length - 3) ||
x.Url == queryTerm.Remove(queryTerm.Length - 4) ||
etc.
Which can be codified as:
var terms = Enumerable.Range(0, queryTerm.Length)
.Skip(1)
.Select(i => queryTerm.Remove(i));
pages = session.Query<MyDocument>()
.Where(x => terms.Contains(x.Url));
Except Raven doesn't supports Contains() like that either. So I coded this up:
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Raven.Client;
using Raven.Client.Embedded;
using Raven.Client.Linq;
namespace RavenTest
{
[TestFixture]
public class HowToDoBackwardsStartsWithInRaven
{
private readonly string[] _testUrls = new[]
{
"www.bad.com",
"www.test.com",
"www.test.com/abc",
"www.test.com/abc/xyz"
};
private readonly string _queryTerm = "www.test.com/abc";
private readonly string[] _expectedResults = new[]
{
"www.test.com",
"www.test.com/abc"
};
[Test]
public void FailsWithContains()
{
List<MyDocument> results;
using (var store = InitStore())
{
LoadTestData(store);
using (var session = store.OpenSession())
{
var terms = GetAllStartingSubstrings(_queryTerm);
results = session.Query<MyDocument>()
.Where(x => terms.Contains(x.Url))
.ToList();
}
}
Assert.That(results.Select(p => p.Url), Is.EquivalentTo(_expectedResults));
}
[Test]
public void SucceedsWithSuperWhere()
{
List<MyDocument> results;
using (var store = InitStore())
{
LoadTestData(store);
using (var session = store.OpenSession())
{
var terms = GetAllStartingSubstrings(_queryTerm);
var query = session.Query<MyDocument>()
.Where(x => x.Url.Length <= _queryTerm.Length);
foreach (var term in terms)
query = query.Where(x => x.Url == term ||
x.Url.Length != term.Length);
results = query.ToList();
}
}
Assert.That(results.Select(p => p.Url), Is.EquivalentTo(_expectedResults));
}
private static IDocumentStore InitStore()
{
var store = new EmbeddableDocumentStore
{
RunInMemory = true,
};
return store.Initialize();
}
private static string[] GetAllStartingSubstrings(string queryTerm)
{
return Enumerable.Range(0, queryTerm.Length)
.Skip(1)
.Select(i => queryTerm.Remove(i))
.ToArray();
}
private void LoadTestData(IDocumentStore store)
{
using (var session = store.OpenSession())
{
foreach (var testUrl in _testUrls)
session.Store(new MyDocument {Url = testUrl});
session.SaveChanges();
}
}
public class MyDocument
{
public string Id { get; set; }
public string Url { get; set; }
}
}
}
Now... I have no idea how efficient the indexing will be on that but the test does pass.

How can I have NHibernate only generate the SQL without executing it?

I know how to log the SQL to log4net/NLog/trace window at runtime with the show_sql configuration option.
What I'm looking for is a way to give a Query<T>() to NHibernate retrieve the generated SQL.
I've looked through the Persister class, the Drivers, different Interceptors and Events. There are so many places to look, even narrowing down my search would be of great help.
You can get the generated sql queries without execution with the following methods:
For the NHibernate.Linq queries:
public String GetGeneratedSql(System.Linq.IQueryable queryable, ISession session)
{
var sessionImp = (ISessionImplementor) session;
var nhLinqExpression = new NhLinqExpression(queryable.Expression, sessionImp.Factory);
var translatorFactory = new ASTQueryTranslatorFactory();
var translators = translatorFactory.CreateQueryTranslators(nhLinqExpression, null, false, sessionImp.EnabledFilters, sessionImp.Factory);
return translators[0].SQLString;
}
For Criteria queries:
public String GetGeneratedSql(ICriteria criteria)
{
var criteriaImpl = (CriteriaImpl) criteria;
var sessionImpl = (SessionImpl) criteriaImpl.Session;
var factory = (SessionFactoryImpl) sessionImpl.SessionFactory;
var implementors = factory.GetImplementors(criteriaImpl.EntityOrClassName);
var loader = new CriteriaLoader((IOuterJoinLoadable) factory.GetEntityPersister(implementors[0]), factory, criteriaImpl, implementors[0], sessionImpl.EnabledFilters);
return loader.SqlString.ToString();
}
For QueryOver queries:
public String GetGeneratedSql(IQueryOver queryOver)
{
return GetGeneratedSql(queryOver.UnderlyingCriteria);
}
For Hql queries:
public String GetGeneratedSql(IQuery query, ISession session)
{
var sessionImp = (ISessionImplementor)session;
var translatorFactory = new ASTQueryTranslatorFactory();
var translators = translatorFactory.CreateQueryTranslators(query.QueryString, null, false, sessionImp.EnabledFilters, sessionImp.Factory);
return translators[0].SQLString;
}
For NHibernate 5.2 in case you want to see actual DbCommand prepared for query (so you can check both SQL in cmd.CommandText and supplied parameters in cmd.Parameters):
//For LINQ
public IEnumerable<DbCommand> GetDbCommands<T>(IQueryable<T> query, ISession s)
{
return GetDbCommands(LinqBatchItem.Create(query), s);
}
//For HQL
public IEnumerable<DbCommand> GetDbCommands(IQuery query, ISession s)
{
return GetDbCommands(new QueryBatchItem<object>(query), s);
}
//For QueryOver
public IEnumerable<DbCommand> GetDbCommands(IQueryOver query, ISession s)
{
return GetDbCommands(query.RootCriteria, s);
}
//For Criteria (needs to be called for root criteria)
public IEnumerable<DbCommand> GetDbCommands(ICriteria rootCriteria, ISession s)
{
return GetDbCommands(new CriteriaBatchItem<object>(query), s);
}
//Adapted from Loader.PrepareQueryCommand
private static IEnumerable<DbCommand> GetDbCommands(IQueryBatchItem item, ISession s)
{
var si = s.GetSessionImplementation();
item.Init(si);
var commands = item.GetCommands();
foreach (var sqlCommand in commands)
{
//If you don't need fully prepared command sqlCommand.Query contains SQL returned by accepted answer
var sqlString = sqlCommand.Query;
sqlCommand.ResetParametersIndexesForTheCommand(0);
var command = si.Batcher.PrepareQueryCommand(System.Data.CommandType.Text, sqlString, sqlCommand.ParameterTypes);
RowSelection selection = sqlCommand.QueryParameters.RowSelection;
if (selection != null && selection.Timeout != RowSelection.NoValue)
{
command.CommandTimeout = selection.Timeout;
}
sqlCommand.Bind(command, si);
IDriver driver = si.Factory.ConnectionProvider.Driver;
driver.RemoveUnusedCommandParameters(command, sqlString);
driver.ExpandQueryParameters(command, sqlString, sqlCommand.ParameterTypes);
yield return command;
}
}
Based on the NHibernate version 3.4 the method for linq expression is:
public String GetGeneratedSql(System.Linq.IQueryable queryable, ISession session)
{
var sessionImp = (ISessionImplementor)session;
var nhLinqExpression = new NhLinqExpression(queryable.Expression,
sessionImp.Factory);
var translatorFactory = new ASTQueryTranslatorFactory();
var translators = translatorFactory.CreateQueryTranslators(nhLinqExpression.Key, nhLinqExpression, null, false,
sessionImp.EnabledFilters, sessionImp.Factory);
var sql = translators.First().SQLString;
var formamttedSql = FormatStyle.Basic.Formatter.Format(sql);
int i = 0;
var map = ExpressionParameterVisitor.Visit(queryable.Expression, sessionImp.Factory).ToArray();
formamttedSql = Regex.Replace(formamttedSql, #"\?", m => map[i++].Key.ToString().Replace('"', '\''));
return formamttedSql;
}
Here is how to get generated Sql from Hql with NH 5.2 (a breaking change in NH 4.0.4 appeared which makes the Hql part of the top voted solution obsolete):
public string HqlToSql(string hql, ISession session)
{
var sessionImp = (ISessionImplementor)session;
var translatorFactory = new ASTQueryTranslatorFactory();
var translators = translatorFactory.CreateQueryTranslators(new NHibernate.Hql.StringQueryExpression(hql),
null, false, sessionImp.EnabledFilters, sessionImp.Factory);
var hqlSqlGenerator = new HqlSqlGenerator(((QueryTranslatorImpl)translators[0]).SqlAST, sessionImp.Factory);
hqlSqlGenerator.Generate();
return hqlSqlGenerator.Sql.ToString();
}