How to select properties with specific attribute using Ndepend - ndepend

I have properties with attribute [Audit] like this
[Audit]
public string WorkPhone
{
get { return workPhone; }
set { workPhone = value; }
}
I need to select all such properties. But there is no predefined domain - Properties at Ndepend. And the query from prop in Methods where prop.HasAttribute("Audit.Audit") select prop
returns no method matched.
So is any option to select properties with attribute exist?

Indeed, you'd need to put your attribute [Audit] on getter and/or setter to use the query:
from prop in Methods where prop.HasAttribute("Audit.Audit") select prop

Related

Does formsflow support setting user task extension value as a variable?

Instead of hardcoding the value of formName in the task extension property of modeler, I need to place the formName value as a variable(e.g., ${formname}).
This is implemented in one of our listeners i.e; FormConnectorListener to get the extension property value in dynamic. Please refer https://github.com/AOT-Technologies/forms-flow-ai/blob/master/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/listeners/task/FormConnectorListener.java
You can add a java listener that should implement org.camunda.bpm.engine.delegate.JavaDelegate and can access the extension property with the general xml api.
public void execute(DelegateExecution execution) throws Exception {
CamundaProperties camundaProperties = execution.getBpmnModelElementInstance().getExtensionElements().getElementsQuery()
.filterByType(CamundaProperties.class).singleResult();
Collection<CamundaProperty> properties = camundaProperties.getCamundaProperties();
for (CamundaProperty property : properties) {
System.out.println(property.getCamundaValue());
}
}
In the above overriden method you can get the variable by using:
execution.getVariable(StringUtils.substringBetween(property.getCamundaValue(), "${", "}"));

How to get the maximum length of a string from an EDMX model in code?

I've created an EDMX object from a database I'm programming against.
I need to get input from a user and save it to a row in the database table. The problem is that I need to limit the length of input strings to the width of the corresponding VARCHAR column in the database.
When I browse the model, I can clearly see in the properties window that the model knows the max length of the string, but I don't know how to access this data in code.
If I want to write something like this:
Entities entities = new Entities();
myTable = entities.myTable.First();
if (userInput.length > myTable.columnA.MaxLength)
{
// tell the user that the input is too long.
}
else
{
myTable.columnA = userInput;
}
How do I write it?
Update: I would like to point out that the IObjectContextAdapater mentioned in the answers below is in the System.Data.Entity.Infrastructure namespace.
Here are two methods by which you can read the meta data:
int? GetMaxLength(DbContext context, string tableName, string propertyName)
{
var oc = ((IObjectContextAdapter)context).ObjectContext;
return oc.MetadataWorkspace.GetItems(DataSpace.CSpace).OfType<EntityType>()
.Where(et => et.Name == tableName)
.SelectMany(et => et.Properties.Where(p => p.Name == propertyName))
.Select (p => p.MaxLength)
.FirstOrDefault();
}
int? GetMaxLength<T>(DbContext context, Expression<Func<T, object>> property)
{
var memberExpression = (MemberExpression)property.Body;
string propertyName = memberExpression.Member.Name;
return GetMaxLength(context, typeof(T).Name, propertyName);
}
So you can either enter the table name and property name, or an expression that specifies the property you're interested in.
Another approach could be to create a MetaData class and use the MaxLength attribute.
It's not very pretty; reading edmx properties at runtime is not something Microsoft exposed easily or documented well (or in some cases, at all). context is your DBContext.
var objectContext = ((IObjectContextAdapter)context).ObjectContext;
var entityType = objectContext.MetadataWorkspace.GetItems<EntityType>(DataSpace.CSpace).Where(e => e.Name == "your entity name").First();
var facets = entityType.Properties["your property name"].TypeUsage.Facets;
facets will look something like this, so you'll need to look for the MaxLength Name(may not exist, depending on the underlying field type) and get the Value:
Count = 5
[0]: Nullable=false
[1]: DefaultValue=null
[2]: MaxLength=250
[3]: Unicode=false
[4]: FixedLength=false
If you modify the T4 template you can add your own attribute to the properties that have MaxLength set.
If you can find the right place to add it, it's something as simple as this:
var lengthAttributeText = edmProperty.MaxLength.HasValue
? string.Format("[MaxLength({0})] ", edmProperty.MaxLength.Value)
: "";
And then add this into the text for the property line. (Tricky to be more detailed since I've already modified my .tt file a lot; also the lack of proper IDE support for .tt files makes this a lot harder than it could be.)

Linq to select top 1 related entity

How can I include a related entity, but only select the top 1?
public EntityFramework.Member Get(string userName)
{
var query = from member in context.Members
.Include(member => member.Renewals)
where member.UserName == userName
select member;
return query.SingleOrDefault();
}
According to MSDN:
"Note that it is not currently possible to filter which related entities are loaded. Include will always bring in all related entities."
http://msdn.microsoft.com/en-us/data/jj574232
There is also a uservoice item for this functionality:
http://data.uservoice.com/forums/72025-entity-framework-feature-suggestions/suggestions/1015345-allow-filtering-for-include-extension-method
The approach to use an anonymous object works, even though it's not clean as you wish it would be:
public Member GetMember(string username)
{
var result = (from m in db.Members
where m.Username == username
select new
{
Member = m,
FirstRenewal = m.Renewals.FirstOrDefault()
}).AsEnumerable().Select(r => r.Member).FirstOrDefault();
return result;
}
The FirstRenewal property is used just to make EF6 load the first renewal into the Member object. As a result the Member returned from the GetMember() method contains only the first renewal.
This code generates a single Query to the DB, so maybe it's good enough for You.

Group By Multiple Columns dynamically

Is there any way how to Group By multiple columns dynamically?
Eg. group x by new { x.Column1, x.Column2 }
but the x.Column1 etc. I want to set dynamically (from UI)
The way to achieve this dynamically on db site is quite complicated as we cannot dynamically create anonymous types. To replace them I would suggest to create a class:
public class CustomTuple<T1, T2>
{
public T1 Item1 { get; set; }
public T2 Item2 { get; set; }
}
We cannot use Tuple here as it does not have default constructor. In CustomTuple class place as much parameters T and as much properties as you would need at max. If you will define in that class 5 properties but for the query you will use only 3 you just set only 3 properties to proper values and the remaining 2 properties you keep null - the query will still work. Alternatively you may dynamically at run time generate proper class with CodeDOM. Then comes query logic:
Type[] parameterTypes = new Type[] { typeof(int), typeof(object) };
Type tupleType = typeof(CustomTuple<,>).MakeGenericType(parameterTypes);
ParameterExpression x = Expression.Parameter(typeof(Entity));
NewExpression body = Expression.New(tupleType.GetConstructor(new Type[0]), new Expression[0]);
MemberBinding binding1 = Expression.Bind(
typeof(CustomTuple<,>).MakeGenericType(parameterTypes).GetProperty("Item1"),
Expression.Property(x, "Value"));
MemberInitExpression memberInitExpression =
Expression.MemberInit(
body,
binding1);
Expression<Func<Entity, object>> exp = Expression.Lambda<Func<Entity, object>>(memberInitExpression, x);
using (MyDbContext context = new MyDbContext())
{
var list = context.Entities.GroupBy(exp).ToList();
}
The above code groups Entities by Value property. parameterTypes may be dynamically build during program execution - this is list of types of properties anonymous type for key selection in group by would have. Basing on that we create proper CustomTuple type. Then we dynamically create at run time binding1 elements - one per each property to be set for grouping key. In the example above I create only one. With use of the NewExpression and MemberBinding expression we may build initialization expression with MemberInit method. Finally you build lambda expression from that and execute it against db.

Using subquery in poco to fill property

I am trying to use a property on a POCO that uses LINQ to ENTITY to pull the first object out of a HashSet property on the same POCO. My object contains the following:
public virtual HashSet<ScheduleWaypoint> ScheduleWaypoints { get; set; }
public ScheduleWaypoint ArrivalStation {
get {
if (this.ScheduleWaypoints != null && this.ScheduleWaypoints.Count() > 0) {
return this.ScheduleWaypoints.Where(row => row.WaypointType.Type.Trim() == "SA").OrderByDescending(row => row.ScheduledTime).First();
} else
return null;
}
}
If I were working with just one object I can't say for certain if this would work but I know that it does not work inside other linq queries. I don't have access to the ID of the ScheduleWaypoint when creating the object, only after it is populated could I possibly do that. Is there a way that I can get this to work? Right now it is telling me:
The specified type member 'ArivalStation' is not supported in LINQ to
Entities. Only initializers, entity members, and entity navigation
properties are supported.
Is there something I can do to get access to this information on a property rather than constantly doing joins when I need the info?
Thanks.
You cannot use custom properties in linq-to-entities query. Only properties mapped directly to the database can be used = you must have sub query directly in your linq-to-entities query returning your ArrivalStation. Perhaps it can be wrapped as simple extension method:
public static IQueryable<ScheduleWaypoint> GetArrivalStation(this IQueryable<ScheduleWaypoints> waypoints, int routeId)
{
return waypoints.Where(w => w.WaypointType.Type.Trim() == "SA" && w.Route.Id == routeId)
.OrderByDescending(w => w.ScheduledTime)
.FirstOrDefault();
}
Where Route is your principal entity where way points are defined. FirstOrDefault is used because sub queries cannot use just First.