0

I am trying to use SqlHierarchyId in .net

In my controller I am using anonymous type to get value from database.

[HttpGet("{id}")]
public async Task<ActionResult<object>> GetDomain(int id)
{
    object domain = from x in _context.Domains.Where(x => x.DomainId == id)
                 select new
                 {
                     Id = x.DomainId,
                     Name = x.DomainName,
                     Type = x.DomainTypeId,
                     Parent = x.Parentt,
                     Path = x.Level.ToString()
                 };
    return domain;
}

Then I want to get the Path to convert to an SqlHierarchyId in order to apply different methods supported by .Net

I've try Reflection:

System.Type type = domain.GetType();
string strNode = (string) type.GetProperty("Path").GetValue(domain, null);

I have this error:

System.NullReferenceException: Object reference not set to an instance of an object.

When I debuged my code I found that strNode is null, but the domain contain all value I need when I test with Postman.

I try Dynamic:

dynamic dyn= domain;
string strNode= dyn.Path;

And I have this error:

Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable<<>f__AnonymousType1>' does not contain a definition for 'Path

I also try several others propositions (Clone, define the anonymous type as a class...) found on similar question but no result.

Note: I am trying to use anonymous type because I can't get the value when direclty use my model. I have a casting error like.

Unable to cast object of type 'Microsoft.SqlServer.Types.SqlHierarchyId' to type 'Microsoft.Data.SqlClient.Server.IBinarySerialize'.

But with anonymous I am able to get the values so I want to access those value and pass it to my model now.

Selim Yildiz
  • 5,254
  • 6
  • 18
  • 28
Ektiva
  • 3
  • 1
  • 1
    I get the "Unable to cast object of type 'Microsoft.SqlServer.Types.SqlHierarchyId' to type 'Microsoft.Data.SqlClient.Server.IBinarySerialize'." error when applying Level.ToString(), i'm using SqlHierachyId type in the entity for Level, are you doing this too ? – Shai Barak Apr 21 '20 at 10:07

2 Answers2

0

Your problem is that domain is actually an IEnumerable of an anonymous object. The select statement generates the IEnumerable even if there's only one instance.

If you want to get the actual object then you can grab it like this.

var obj = domain.FirstOrDefault();

or

var obj = domain.Single();

And then do your reflection lookup:

var type = obj.GetType();
var strNode = (string) type.GetProperty("Path").GetValue(obj, null);
Sean
  • 60,939
  • 11
  • 97
  • 136
  • I used to add FirstOrDefault() directly after the select clause. It's not working when I apply it in a new statement. But this was the idea. – Ektiva Mar 11 '20 at 17:35
0

The main issue or assumption is with the return value from GetDomain Action. Linq Where returns collection (of type on which you are applying this filter), and hence in this case domain will hold anonymous IQueryable as opposed to single domain.

If you want to return single domain, then please use FirstOrDefault as shown below:

[HttpGet("{id}")]
public async Task<ActionResult<object>> GetDomain(int id)
{   
    object domain = (from x in _context.Domains.Where(x => x.DomainId == id)
                 select new
                 {
                     Id = x.DomainId,
                     Name = x.DomainName,
                     Type = x.DomainTypeId,
                     Parent = x.Parentt,
                     Path = x.Level.ToString()
                 }).FirstOrDefault();
    /*    
    // Or use FirstOrDefault in place of Where as shown below                
     object domain = (from x in _context.Domains
                 select new
                 {
                     Id = x.DomainId,
                     Name = x.DomainName,
                     Type = x.DomainTypeId,
                     Parent = x.Parentt,
                     Path = x.Level.ToString()
                 }).FirstOrDefault(x => x.Id == id);
    */
    return domain;
}

After this change, your rest of code should work as expected.

sam
  • 1,937
  • 1
  • 8
  • 14