This project has moved and is read-only. For the latest updates, please go here.

Cannot resolve a Relative URI Reference since there is no in-scope Base URI!

Jun 16, 2014 at 6:19 PM
Hi.

I have installed and configured BrighstarDB against Sesame triple store.
I connect with a query processor with empty default uri
When I call ctx.IdentifiedObjects.toList(), things work Ok. I can retrieve loads of objects.
But if I try to execute a "Where" (.Where(c =>c == aobject) -query, I get "Cannot resolve a Relative URI Reference since there is no in-scope Base URI!"

If I then try with a default uri (the same as the context in sesame), I get no error, but also no data.

The data I try to get, has no default graph (or context).

Can anyone shed some light on this please? How is it supposed to be used?

B
Jun 17, 2014 at 9:50 AM
Hi,

It sounds like the SPARQL query that is being generated from the LINQ is somehow invalid - without knowing a bit more about your setup though it is hard to diagnose.

Can you post a more complete example (or a link to a GitHub Gist containing the code) - your example should include at least the interface definition for IIdentifiedObject and the code you used to create aobject as well as the query itself.

Cheers

Kal
Jun 18, 2014 at 11:32 AM
Edited Jun 19, 2014 at 8:56 AM
Hi.

Thanks for the reply!

I have used the nuget installed packages:
BrighstarDB: 1.6.2.0
dotNetRDF 1.0.3.0

Please see code below for reference.
  1. I run as listed in program.cs.
    All lists contains data, including IdentifiedObjects3
  2. I change IdentifiedObjects3 to:
    var IdentifiedObjects3 = ctx.IdentifiedObjects.Where(c => c == IdentifiedObjects1).ToList();
    RdfParseException: Cannot use an Empty URI to refer to the document Base URI since there is no in-scope Base URI!
  3. I use endpoint like this:
    SparqlRemoteEndpoint endpoint = new SparqlRemoteEndpoint(new Uri("http://xxx.xxx.no:9090/openrdf-sesame/repositories/DS44SNEQV1621"), defaultGraphUris);
    Thus, with default uri, same as the context in Sesame
    IdentifiedObjects1 to 3 are empty and exception occurs
    Using sparql directly against sesame, I see that the objects in question doesn't have context. Is this the problem?
  4. var IdentifiedObjects3 = ctx.IdentifiedObjects.Where(c => c.MRID == IdentifiedObjects1.MRID).ToList();
    works (or with name etc))
Commenting in or
[Identifier()]
string Id { get; }
does not seem to make any difference, but the line
var IdentifiedObjects3 = ctx.IdentifiedObjects.Where(c => c.Id == IdentifiedObjects1.Id).ToList();
does not give results. In debugger, I see that Id values are like:
"file://ds4_sn1621_cim15_20140328_r4.xml/#_db2ac01a-1d03-c184-e040-1e828c946f5c"
whereas sparql query looks like:
file://DS4_SN1621_CIM15_20140328_R4.xml#_9bb00fa1-c338-831a-e040-1e828c94e833
Are capital letters an issue here?

For the time being I can use .MRID (or names), but not all classes have MRID, so in the end I really need to resolve the identity question.

The code(removed comments etc)
program.cs:
        List<Uri> defaultGraphUris = new List<Uri>();
        defaultGraphUris.Add(new Uri("file://DS4_SN1621_CIM15_20140328_R4.xml"));
        //defaultGraphUris.Add(new Uri("file:"));
        SparqlRemoteEndpoint endpoint = new SparqlRemoteEndpoint(new Uri("http://xxx.xxx.no:9090/openrdf-sesame/repositories/DS44SNEQV1621"));
        SparqlRemoteUpdateEndpoint updateEndPoint = new SparqlRemoteUpdateEndpoint(new Uri("http://xxx.xxx.no:9090/openrdf-sesame/repositories/DS44SNEQV1621"));
        RemoteQueryProcessor queryProcessor = new RemoteQueryProcessor(endpoint);
        RemoteUpdateProcessor updateProcessor = new RemoteUpdateProcessor(updateEndPoint);
        var doContext = new SparqlDataObjectContext(queryProcessor, updateProcessor, false);



        Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;

        var store = doContext.OpenStore("sparql");
        var ctx = new MyEntityContext(store);

        //var ctx = new MyEntityContext(connectionString);


        var powerSystemParticipants = ctx.PowerSystemParticipants.Where(c => c.Name == "HAFSLUND").ToList().FirstOrDefault();


        var IdentifiedObjects1 = ctx.IdentifiedObjects.Take(1).ToList().FirstOrDefault();
        var IdentifiedObjects2 = ctx.IdentifiedObjects.Take(4).ToList();
        var IdentifiedObjects3 = ctx.IdentifiedObjects.Where(c => c.MRID == IdentifiedObjects1.MRID).ToList();           

        if (IdentifiedObjects2.Contains(IdentifiedObjects1))
        {
            Console.WriteLine("HH");
        }

        var IdentifiedObjects4 = IdentifiedObjects2.Where(c => c == IdentifiedObjects1).ToList().FirstOrDefault();
The IdentifiedObject.cs:
[Entity("cim:IdentifiedObject")]
public interface IIdentifiedObject
{
    [Identifier()]
    string Id { get; }

    [PropertyType("cim:IdentifiedObject.aliasName")]
    string AliasName
    {
        get;
        set;
    }

    [PropertyType("SN:IdentifiedObject.shortName")]
    string ShortName
    {
        get;
        set;
    }

    [PropertyType("cim:IdentifiedObject.localName")]
    string LocalName
    {
        get;
        set;
    }

    [PropertyType("cim:IdentifiedObject.description")]
    string Description
    {
        get;
        set;
    }

    [PropertyType("cim:IdentifiedObject.name")]    
    string Name
    {
        get;
        set;
    }

    [PropertyType("cim:IdentifiedObject.mRID")]
    string MRID
    {
        get;
        set;
    }
}
Thanks,

B
Jun 19, 2014 at 4:13 PM
Edited Jun 19, 2014 at 4:16 PM
Hi.
There is a couple of other things as well:

When I tried to log, using Logging.EnableProfiling(true);
However, I get no logging for var ctx = new MyEntityContext(store); where store is IDataObjectStore (and further nothing). If I use a connect string instead, I do get logging. Is logging not implemented for the first situation? Any settings?

I have two classes where both are inverse on one another. Please see code below.
The single reference is fetched form the database, while the list is empty
I tried the following query:

var hafslundAcLineSegments =(from acLineSegment in ctx.ACLineSegments
join powerSystemRoleShareQ in powerSystemRoleSharesHafslundII on acLineSegment.MRID equals powerSystemRoleShareQ.PowerSystemResource.MRID select (acLineSegment));

It's very slow. When I change

"from acLineSegment in ctx.ACLineSegments"

to

"from acLineSegment in ctx.ACLineSegments.take(10)"

it returns within reasonable time with values. How is the Sparql generated. If I do it by hand, it's quite quick. I was hoping to see the Sparql generated, therefore I was looking for the logging.

public interface IPowerSystemResource : IIdentifiedObject
{

    [Identifier()]
    string Id
    {
        get;
    }

    ICollection<IOperatingShare> OperatingShare
    {
        get;
        set;
    }
}
[Entity("cim:OperatingShare")]
public interface IOperatingShare
{

    [Identifier()]
    string Id
    {
        get;
    }

    [PropertyType("cim:OperatingShare.PowerSystemResource")]       
    IPowerSystemResource PowerSystemResource
    {
        get;
        set;
    }
}
Br

Bernt
Jun 19, 2014 at 6:18 PM
Hi Bernt,
Please see code below for reference.
  1. I run as listed in program.cs.
    All lists contains data, including IdentifiedObjects3
  2. I change IdentifiedObjects3 to:
    var IdentifiedObjects3 = ctx.IdentifiedObjects.Where(c => c == IdentifiedObjects1).ToList();
    RdfParseException: Cannot use an Empty URI to refer to the document Base URI since there is no in-scope Base URI!
  3. I use endpoint like this:
    SparqlRemoteEndpoint endpoint = new SparqlRemoteEndpoint(new Uri("http://xxx.xxx.no:9090/openrdf-sesame/repositories/DS44SNEQV1621"), defaultGraphUris);
    Thus, with default uri, same as the context in Sesame
    IdentifiedObjects1 to 3 are empty and exception occurs
    Using sparql directly against sesame, I see that the objects in question doesn't have context. Is this the problem?
I think it might be - because you set up the default graph to be a named context, if the objects are in the Sesame default context, they won't get found by the query. Try creating the remote endpoint without specifying any default graph URIs.
  1. var IdentifiedObjects3 = ctx.IdentifiedObjects.Where(c => c.MRID == IdentifiedObjects1.MRID).ToList();
    works (or with name etc))
Commenting in or
[Identifier()]
string Id { get; }
does not seem to make any difference, but the line
var IdentifiedObjects3 = ctx.IdentifiedObjects.Where(c => c.Id == IdentifiedObjects1.Id).ToList();
does not give results. In debugger, I see that Id values are like:
"file://ds4_sn1621_cim15_20140328_r4.xml/#_db2ac01a-1d03-c184-e040-1e828c946f5c"
whereas sparql query looks like:
file://DS4_SN1621_CIM15_20140328_R4.xml#_9bb00fa1-c338-831a-e040-1e828c94e833
Are capital letters an issue here?
I'm not sure, it could be if Sesame treats the file:// URI as case-sensitive. I'm not quite sure why there are case differences here. Which SPARQL query are you looking at? Is it the one that is generated by the entity framework code ?
For the time being I can use .MRID (or names), but not all classes have MRID, so in the end I really need to resolve the identity question.
One thing to try here - reimport the RDF file into a new Sesame store (or a new context) but this time give it an explicit Base URI using http (e.g. http://data.xxx.xxx.no/ds4_sn1621_cim15_20140328_r4.xml). That would at least eliminate the file:// protocol as being a problem.

Also I see in your code that you have declared the entity type and property types with a CURIE - so I guess that somewhere in your code you also have:
[assembly: NamespaceDeclaration("cim", "http://some.uri/here")]
I think you would get a different (more helpful) exception if you were missing this, but it is worth double checking.

In summary I think:
a) Try querying with no default graph set - this will query all the contexts in the Sesame store and eliminates the "oh the resources are in the wrong context" possibility.
b) Try reimporting the RDF so your resources have http URIs rather than file URIs - if this turns out to fix the problem please let me know as I'll need to look into how we can fix that for the future.

Cheers

Kal
Jun 19, 2014 at 6:27 PM
Bernt wrote:
Hi.
There is a couple of other things as well:

When I tried to log, using Logging.EnableProfiling(true);
However, I get no logging for var ctx = new MyEntityContext(store); where store is IDataObjectStore (and further nothing). If I use a connect string instead, I do get logging. Is logging not implemented for the first situation? Any settings?
Logging goes to a .NET TraceSource which you will need to configure to output to a file. See http://brightstardb.readthedocs.org/en/latest/Running_BrightstarDB/#configuring-logging for more information.
I have two classes where both are inverse on one another. Please see code below.
The single reference is fetched form the database, while the list is empty
I tried the following query:

var hafslundAcLineSegments =(from acLineSegment in ctx.ACLineSegments
join powerSystemRoleShareQ in powerSystemRoleSharesHafslundII on acLineSegment.MRID equals powerSystemRoleShareQ.PowerSystemResource.MRID select (acLineSegment));

It's very slow. When I change

"from acLineSegment in ctx.ACLineSegments"

to

"from acLineSegment in ctx.ACLineSegments.take(10)"

it returns within reasonable time with values. How is the Sparql generated. If I do it by hand, it's quite quick. I was hoping to see the Sparql generated, therefore I was looking for the logging.
In the SPARQL you write by hand are you just SELECTing the URI or are you CONSTRUCTing an RDF graph. The EntityFramework will create a query that eager loads the triples for the entities you are asking for. The LINQ query as you have it in your code will translate to a SPARQL query that builds an RDF graph with all of the properties of all ACLineSegments that match the criteria - if there are many, or if they have many properties, that will be slow. If you actually just want the identifier then change your LINQ query to:

(from acLineSegment in ctx.ACLineSegments
join powerSystemRoleShareQ in powerSystemRoleSharesHafslundII on acLineSegment.MRID equals powerSystemRoleShareQ.PowerSystemResource.MRID
select (acLineSegment.Id)); // or .MRID ?

...and see how that performs. It should be better because it will translate to a SELECT query and just get the URI for each matching ACLineSegment, but of course then you need to go and load each ACLineSegment entity separately. You can also use your LINQ query to construct an anonymous object so if you just want a couple of properties of each entity that is definitely the way to go (again it gets translated to a SELECT query).

Cheers

Kal