So I'm trying to get a list of relation existing between two table to validate some integration test.
The database is pretty simple : Table1 <- RelationTable -> Table2
I would like to get the existing relation from a list of Table1 Ids or a list of Table2 Ids or both.
If I said that my parameter are all optional, I need to verify that both aren't null or throw a exception if so. If I force both parameter and want to allow one or the other to be null, but not both, I need to create 3 methods to handle it or force the dev who will use the method to add null parameter in the call like the code below which I think it's a ugly way to do it.
Sadly this couldn't be polymorphism because the first params is the same type...
But I would like to allow methodX to just be call method and allow the 3 possible methods into one without allowing method() with no params to be use.
protected async Task<List<Relation>> method1(List<string> table1Ids) => method3(table1Ids, null);
protected async Task<List<Relation>> method2(List<string> table2Ids) => method3(null, table2Ids);
protected async Task<List<Relation>> method3(List<string> table1Ids, List<string> table2Ids)
{
if(table1Ids == null && table2Ids == null)
throw new ArgumentNullException();
// code here
}
To be honest, I could choose if all null throw or 3 method or for bulletproof code choose both and it would work fine, but I'm searching alternate version where I can force a minimum of one parameter but don't said which one is required. I thought maybe attribute from the .Net Framework would do that for me, but I couldn't find something near that. I'm searching for something that could do that out of the box or a custom attribute to do that.
It would be code something like that. Without the if throw because the attribute would validate it.
[MinimumOptionalRequiredAttribute(1)]
protected async Task<List<Relation>> GetRelationFromListOfIds(List<string> table1Ids = null,
List<string> table2Ids = null) {
// code here
}
// Example of code that could be use
{
// Those would work
var byTable1 = GetRelationFromListOfIds(table1Ids);
var byTable2 = GetRelationFromListOfIds(table2Ids:table2Ids);
var byTable1And2 = GetRelationFromListOfIds(table1Ids, table2Ids);
// This would not be allow by the c# intellisense
var throwException = GetRelationFromListOfIds();
}
I know I'm trying to solve everything with one method instead of going with a more "normal" way. I talk about attribute, but it not necessary an attribute. I would expect the code to not compile if you try call methodEmptyParamsNotAllow(). To be honest, I'm not even sure if that is a good idea for code readability. I'm just curious about the idea. Is something similar already exist? Is the idea good? What it would look like?
Related
I am following this tutorial, https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/tutorials/how-to-write-csharp-analyzer-code-fix
What I really want is to detect if a method in a ASP.Net Web API controller is missing my Custom attribute and give hints to the developer to add it.
In my Analyzer's Initilize method, I have chosen MethodDeclaration as the SyntaxKind like this
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.MethodDeclaration);
In the AnalyzeNode method, I want to detect if the method in question already has the Custom attribute added to it.
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
var methodDeclaration = (MethodDeclarationSyntax)context.Node;
// make sure the declaration isn't already const:
if (methodDeclaration.AttributeLists.Any(x=> x. ))
{
return;
}
Not sure what needs to be done in this piece of code to find if Custom attribute is already applied.
Eventually I want my code analyzer to let the user add the missing attribute
[Route("/routex")]
[Custom()]
public async Task<IHttpActionResult> AlreadyHasCustomAttribute()
{
//everything is good, no hint shown to the user
}
[Route("/routey")]
public async Task<IHttpActionResult> DoesNotHaveCustomAttribute()
{
//missing Custom attribute, show hint to the user and add the attribute as a code fix
}
Please suggest a solution. Thanks.
The easiest thing might be to simply call methodDeclaration.AttributeLists.Any()) just to verify it has attributes at all before proceeding for performance reasons. Once it does, you can call context.SemanticModel.GetDeclaredSymbol(methodDeclaration) and that'll give you an IMethodSymbol which you can call GetAttributes() on. From there, you can walk the list of attributes and find the one you're looking for (or in this casel, find the lack of it.)
There isn't one way to do it. The way I'd personally do this is to first register a compilation start action and get the attribute symbol. Then register a symbol action, and for each method check if any of the attributes match the attribute obtained in compilation start.
This would look similar to the following
context.RegisterCompilationStartAction(context =>
{
var targetAttribute = context.Compilation.GetTypeByMetadataName("FullyQualifiedAttributeName");
if (targetAttribute is null)
{
// Do whatever you want if the attribute doesn't exist in the first place.
// Stopping the analysis is probably the best option?
return;
}
context.RegisterSymbolAction(context =>
{
var methodSymbol = (IMethodSymbol)context.Symbol;
if (!methodSymbol.GetAttributes().Any(attrData => targetAttribute.Equals(attrData.AttributeClass, SymbolEqualityComparer.Default))
{
// attribute is missing.
// though it doesn't make sense to report a missing attribute for all methods in a compilation, so you'll likely need extra checks based on the logic of your analyzer.
}
}, SymbolKind.Method);
});
I am developing an ASP.NET Core API that uses events with MediatR to publish them in the system. I am looking to include a scheduling service to the Api where events are stored in a database and pull out later and published using MediatR.
The issue I have is that the objects are stored in the database as jsonb and I need to be able to draw them out and cast them to specific object types. I can store the name of the type in the database and access the type that way. However I can't find a solution to this online.
If there is a better way to do this who thing that would be helpful too, but I'm looking for a solution that looks something like this:
var eventType = Type.GetType("foo");
var eventObject = obj.ToObject<eventType>();
If there is a better way of doing this please let me know!
Thanks.
Assuming you could figure out a way to do this, how exactly do you intend to use eventObject after you've managed to create it? Its type is not known at compile time, so you can't write code that uses its methods and properties, because you don't know what methods and properties it has.
For example, if you have a "foo" type with a DoFoo() method and a "bar" type with a DoBar() method, how do you know whether to call DoFoo() or DoBar()?
var eventType = Type.GetType("foo");
var eventObject = obj.ToObject<eventType>();
eventObject.DoFoo(); //How do you know to do this?
eventObject.DoBar(); //How do you know to do this?
The best you can do is a series of if statements:
if (eventType) == typeof(foo))
{
eventObject.DoFoo();
}
if (eventType) == typeof(bar))
{
eventObject.DoBar();
}
Well, if you're going to do that, you may as well cast it in the same if block, which eliminates your problem.
if (obj.GetType() == typeof(foo))
{
((foo)obj).DoFoo();
}
if (obj.GetType() == typeof(bar))
{
((bar)obj).DoBar();
}
If you don't actually need any of its properties or methods, and only need to be able to pass it to some generic method, you can just pass it along as an object. Getting the method is a little tricky though:
mediatR.GetType()
.GetMethod("Publish");
.MakeGenericMethod(eventType);
.Invoke(obj, null);
I am writing unit tests with Specflow 3, to test a method that query data in db and I use NFluent to have nice assertions methods.
Is there any way to smoothly test equality over a few members of an object ?
There is a method called HasFieldsWithSameValues but I found nothing in their wiki that explains how to use it thoroughly. There is a Excluding("fieldNames","etc",...) method that we can chain, but I would have to exclude over 20 public members.
Here is my feature file ( functionnal scenario, Gherkin syntax )
Scenario: TimeSheet_001_SearchForExistingTimeSheet
When I search for timesheet with id 31985
Then I get the following timesheet
| id | StatutPaid | StatutFact |
| 31985 | Paid | None |
Then I have the methods called by this code bloc :
[When(#"I search for timesheet with id (.*)")]
public void WhenJeChercheLeReleveDHeureAvecLId(int id)
{
var result = GetTimeSheetDetailQuery(id);
timeSheetContext.Result = result;
}
[Then(#"I get the following timesheet")]
public void ThenJObtiensLeReleveDHeureSuivant(Table table)
{
var sut = table.CreateInstance<TimeSheetDetail>();
Check.That(sut).HasFieldsWithSameValues<TimeSheetDetail>().Fields.IsEqualTo(timeSheetContext.Result);
}
The problem is that TimeSheetDetail is a VERY detailed object, I just need to check for 3 members for this case of test.
is there a way to write for example
//this
Check.That(sut)
.HasFieldsWithSameValues<myType>("Id","StatusPaid","StatusFact")
.IsEqualTo(timeSheetContext.Result);
//instead of this
Check.That(sut.Id).IsEQualTo(timeSheetContext.Result.Id);
Check.That(sut.StatusPaid).IsEQualTo(timeSheetContext.Result.StatusPaid);
Check.That(sut.StatusFact).IsEQualTo(timeSheetContext.Result.StatusFact);
You can achieve desired results using an anonymous type for the expected value.
Check.That(sut).HasFieldsWithSameValues(new {Id=1, StatusPaid = true, StatusFact = "Paid"});
In this way, you can focus the comparison of the fields of interests.
If you need to make many check like this, you should contemplate creating a simple dedicated type for this instead of an anonymous one.
From the sound of things, the exact functionality that you're looking for isn't directly supported by NFluent. This sounds like a good candidate for using C# extension methods, and fortunately NFluent supports extension methods.
The gist of the idea is that you can implement a method that contains the logic that you're trying to have, and this method can be directly called by NFluent in order to achieve the syntax that's closer to what you're looking for (if not exactly what you're looking for). After implementing such method, you'll be able to make a call like so:
Check.That(sut).HasFieldsWithSameValues(timeSheetContext.Result, "Id", "StatusPaid", "StatusFact");
The extension method's prototype would be something like this:
public static ICheckLink<ICheck<Object>> HasFieldsWithSameValues(this ICheck<Object> check, myType myObject, params string[] fieldsList)
Note that you may be able to get the exact syntax that you're looking for, but you'll have to do a little bit more work to figure out how to do that in the context of extension methods.
Find out more about C# extension methods here.
Find an example of how to implement NFluent extension methods here.
I did a research I not found anything so far. Appreciate your help.
As the title says, I'm adding a record to my DbContext by doing a query, and if it returns a null value then I create the record. Otherwise, I modify it.
My question is: Is this a good practice or I shouldn't do this that way? The code is like this:
var desiredEntity = MyDbContext.SingleOrDefault(x => x.Name == "Rob");
if (desiredEntity == null)
{ desiredEntity = new DbSetOfEntity()... //create if doesn't exists }
else
{ desiredEntity.ValueToModify == 3; }
MyDbContext.SaveChanges()
What is the difference between this and creating an entity explicitly and adding it with the DbContext.Add() method?
Edit:
A similar question here is asked, but I don't want to use AddOrUpdate method or Attach and changing the state of the entities manually. I just want to know if my approach is not problematic and what are the differences by using the conventional .Add(myEntity) approach.
AddOrUpdate() is checking record for existance by EntityKey. So if x.Name which you are checking is not Key - your approach is correct.
Also as you have only name value as an input parameter ("Rob") you will have to request record from context, and you will have it attached. So then you can just change it as you need and the changes will be tracked automatically. Alternatively, create it if it doesn't exist and call Add().
Taking into account the above your approach is OK and will work and I dont see any problems with it.
On the other hand, your code should be as simple and elegant as it can be. It is important for supporting your code by you or by your teammates. That is why using constructions like AddOrUpdate or other built-in stuff is good practice. But not a law.
P.S. I am not looking at code like { desiredEntity.ValueToModify == 3; }. This is potentially bad practice as 3 should perhaps be passed to your method as a parameter.
I have a large number of PL/SQL stored procs that return columns with single character strings representing some kind of status value from a fixed range. In the project I'm working on, these columns have been mapped by Dapper to string properties on the domain objects, which are awkward and unreliable to manage, so I'd like to switch to enums.
If I used enums with single character names like enum Foo {A, P} I'm pretty sure Dapper would map them correctly but I don't want that, I want enums with descriptive labels like so:
enum Foo {
[StringValue("A")]
Active,
[StringValue("P")]
Proposed
}
In the above example, StringValueAttribute is a custom attribute and I can use reflection to convert the "A" to Foo.Active, which works fine - except I need Dapper to perform that conversion logic for me. I wrote a custom type handler to do this:
public class EnumTypeHandler<T> : SqlMapper.TypeHandler<T>
{
public override T Parse(object value)
{
if (value == null || value is DBNull) { return default(T); }
return EnumHelper.FromStringValue<T>(value.ToString());
}
public override void SetValue(IDbDataParameter parameter, T value)
{
parameter.DbType = DbType.String;
parameter.Value = EnumHelper.GetStringValue(value as Enum);
}
}
//Usage:
SqlMapper.AddTypeHandler(typeof(Foo),
(SqlMapper.ITypeHandler)Activator.CreateInstance(typeof(EnumTypeHandler<>).MakeGenericType(typeof(Foo)));
The registration with SqlMapper.AddTypeHandler() seems to work fine, but when my DbConnection.Query() code runs, I get an error saying that the value 'A' could not be converted - the error is thrown from Enum.Parse, suggesting that Dapper isn't actually calling my type handler at all despite it being registered. Does anyone know a way around this?
Another user has reported this as an issue on Dapper's github site. Seems like it's a deliberate optimisation specifically around enums in Dapper, so I've changed my database model rather than trying to change the mapping code. I looked at trying to modify Dapper itself, but the source code of Dapper is optimised like nothing I've ever seen, emitting opcodes to perform conversions in the most performant way possible - no way I want to start trying to work out how to make changes there.